In his 1987 paper (Cognitive Social Structures), Krackhardt includes
data from a 21-member network of managers (all male) at a tech
manufacturing company. These data include not only egocentric reports
(these are the people I go to for advice), but also allocentric
reports (I think John often asks Bill for advice). We can try testing
whether multistep relational abstraction explains the subjects’
allocentric beliefs in this dataset.
Setup
# Set a random seed for reproducibility
set.seed(sum(utf8ToInt("krackhardt")))
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.2 ✔ readr 2.1.4
## ✔ forcats 1.0.0 ✔ stringr 1.5.0
## ✔ ggplot2 3.4.3 ✔ tibble 3.2.1
## ✔ lubridate 1.9.2 ✔ tidyr 1.3.0
## ✔ purrr 1.0.2
## ── Conflicts ────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(here)
## here() starts at /Users/jaeyoungson/Documents/GitHub/multistep-relational-abstraction
library(tidygraph)
##
## Attaching package: 'tidygraph'
##
## The following object is masked from 'package:stats':
##
## filter
library(ggraph)
library(patchwork)
library(lme4)
## Loading required package: Matrix
##
## Attaching package: 'Matrix'
##
## The following objects are masked from 'package:tidyr':
##
## expand, pack, unpack
library(lmerTest)
##
## Attaching package: 'lmerTest'
##
## The following object is masked from 'package:lme4':
##
## lmer
##
## The following object is masked from 'package:stats':
##
## step
library(broom.mixed)
kable <- knitr::kable
vif <- car::vif
knitting <- knitr::is_html_output()
if (knitting) {
# Create directories for saving stuff
if (!dir.exists(here("outputs"))) {
dir.create(here("outputs"))
}
if (!dir.exists(here("outputs", "07-krackhardt"))) {
dir.create(here("outputs", "07-krackhardt"))
}
}
# Pull in some modeling tools
source(here("code", "utils", "representation_utils.R"))
source(here("code", "utils", "network_utils.R"))
gg <- list(
theme_bw(),
theme(
plot.title = element_text(hjust = 0.5, size = 13),
plot.subtitle = element_text(hjust = 0.5, size = 11),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.spacing = unit(0.75, "lines"),
legend.box.spacing = unit(0.5, "lines"),
legend.margin = margin(c(0, 0, 0, 0), unit = "lines")
)
)
plot_representation <- function(rep_df, relation_value, n_breaks = 3) {
plot_df <- rep_df %>%
filter(from != to) %>%
group_by(from, to) %>%
summarise(value = mean({{relation_value}}), .groups = "drop")
plot_df %>%
# Plot
mutate(
across(c(from, to), factor),
from = fct_rev(from)
) %>%
ggplot(aes(x=to, y=from, fill=value)) +
gg +
geom_tile() +
coord_fixed() +
scale_fill_viridis_c(
option = "magma", name = NULL, na.value = "white", n.breaks = n_breaks
) +
theme(
legend.position = "bottom",
axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1)
)
}
check_significance <- function(tidy_stats) {
tidy_stats %>%
mutate(
significance = case_when(
p.value < 0.001 ~ "***",
p.value < 0.01 ~ "**",
p.value < 0.05 ~ "*",
p.value < 0.1 ~ ".",
TRUE ~ ""
)
)
}
These data are included in Krackhardt 1987, Appendix A. Each
allocentric CSV contains an adjacency matrix, so we’ll need to do a
little work to get them into a tidy-friendly format.
The “egocentric” network is defined in the way that social networks
are most often defined: based on each subject’s answer to the question,
“Who are you connected to?” Oftentimes, this question is phrased to
measure friendships (e.g., “Are you friends with X?”). In this
particular dataset, the question is something closer to “Who do you ask
for advice?”
The “allocentric” cognitive maps measure each subject’s answer to the
question, “Does X ask Y for advice?” This includes the special case of,
“Does X ask you for advice?” Here’s the rationale for including the
special case in allocentric maps. Imagine for a moment that this were a
study about friendships instead of advice-giving. In that case, we would
consider “Are you friends with X?” to be a question that subjects would
know the answer to (or at least, they would know better than anyone
else). On the other hand, we would consider the question “Does X
consider you a friend?” to be more of an inference than knowledge. I
don’t know whether X considers me a friend; I don’t consider X to be a
friend, but we do occasionally eat lunch together. Moreover, in cases of
disagreement (X says he asks Y for advice; Y doesn’t agree), the “ground
truth” egocentric network would then hinge on the researcher’s decision
to use an intersection vs union rule to resolve disagreements;
Krackhardt notes this in his paper. By alternatively defining the
egocentric network based solely on the responses that subjects would
have greatest introspective access to (their own advice-seeking
behavior), we sidestep this researcher degree of freedom.
krackhardt_raw <- here("data", "krackhardt") %>%
fs::dir_ls(regexp = "krackhardt_tech_managers_sub[[:digit:]]{2}\\.csv") %>%
map_dfr(
.f = ~read_csv(.x, col_names = FALSE, show_col_types = FALSE),
.id = "filename"
) %>%
mutate(
sub_id = str_extract(filename, "sub[[:digit:]]{2}"),
sub_id = str_remove(sub_id, "sub"),
sub_id = as.numeric(sub_id)
) %>%
select(-filename) %>%
group_by(sub_id) %>%
mutate(from = row_number()) %>%
ungroup() %>%
pivot_longer(
cols = -c(sub_id, from),
names_to = "to",
values_to = "edge"
) %>%
mutate(
to = str_remove(to, "X"),
to = as.integer(to)
)
krackhardt_egocentric <- krackhardt_raw %>%
filter(sub_id == from, from != to) %>%
select(-sub_id)
krackhardt_allocentric <- krackhardt_raw %>%
filter(sub_id != from, from != to)
Plot data
Okay, let’s try and get a sense for what the “egocentric” network
looks like.
krackhardt_g <- krackhardt_egocentric %>%
filter(edge == 1) %>%
select(-edge) %>%
tbl_graph(edges = .) %>%
mutate(name = row_number())
plot_network_graph <- krackhardt_g %>%
mutate(Degree = centrality_degree(mode = "in")) %>%
# Plot the "ground truth" network
ggraph(layout = "stress") +
geom_edge_link(
aes(
start_cap = label_rect(node1.name, padding = margin(15, 15, 15, 15)),
end_cap = label_rect(node2.name, padding = margin(15, 15, 15, 15)),
),
arrow = arrow(length = unit(5, "pt"), type = "closed")
) +
geom_node_label(
aes(label = name, size = Degree),
fill = "grey95", show.legend = FALSE
) +
scale_size(range = c(3, 10)) +
theme(
panel.background = element_blank(),
strip.background = element_blank(),
panel.border = element_blank(),
axis.title = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
plot.title = element_text(hjust = 0.5, size = 13),
strip.text = element_text(hjust = 0.5, size = 13),
legend.position = "bottom"
)
plot_network_graph
## Warning: Using the `size` aesthetic in this geom was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` in the `default_aes` field and elsewhere instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was generated.

We can also plot this as a matrix instead of a graph, which will ease
comparison with the cognitive strategies we’ll consider next.
plot_network_adj <- krackhardt_egocentric %>%
plot_representation(edge, n_breaks = 2) +
ggtitle("Egocentric Network")
plot_network_adj

How does this compare to subjects’ mental representation of the
network?
plot_choice <- krackhardt_allocentric %>%
plot_representation(relation_value = edge) +
ggtitle("Network Representation")
plot_network_adj | plot_choice

In the original paper, Krackhardt makes the following note: “There
are some centers of focus for advice, notably 2 and 21 (both are vice
presidents) … In [the subjectively perceived network], 21 loses his
prominence as a major recipient of nominations: instead, 18, 14, and 7
(the president) appear to be more central.” To get a quantitative sense
for this in our data, we can try calculating the “perceived” degree
centrality by summing over the matrix columns, then comparing that
against the “true” in-degree centrality.
centrality_differences <- krackhardt_g %>%
mutate(
Degree = centrality_degree(mode = "in"),
Betweenness = centrality_betweenness(directed = TRUE)
) %>%
as_tibble() %>%
# Add represented in-degree; standardize sum by number of network members
left_join(
krackhardt_allocentric %>%
group_by(name = to) %>%
summarise(Perceived = sum(edge)/21, .groups = "drop"),
by = c("name")
) %>%
select(name, Perceived, everything()) %>%
arrange(desc(Degree), desc(Perceived))
We can see that the same number of managers go to subjects 18 and 21
for advice (15 each), but that subject 18 is perceived as being much
more “popular” (averaged across subjects, 11.95 managers are perceived
to go to him for advice) than subject 21 (averaged across subjects, 8.38
managers are perceived to go to him for advice). A similar phenomenon
happens with subjects 1 and 7, where subject 1 is perceived as being
much less popular than subject 7, despite their having the same “true”
popularity.
centrality_differences %>%
ggplot(aes(x=Degree, y=Perceived)) +
gg +
geom_smooth(method = "lm", se = FALSE) +
geom_label(aes(label = name)) +
scale_x_continuous(name = "True (degree) centrality") +
scale_y_continuous(name = "Perceived centrality")
## `geom_smooth()` using formula = 'y ~ x'

centrality_differences %>%
select(name, Degree, Perceived) %>%
kable()
| 2 |
18 |
13.047619 |
| 18 |
15 |
11.952381 |
| 21 |
15 |
8.380952 |
| 7 |
13 |
10.380952 |
| 1 |
13 |
5.095238 |
| 11 |
11 |
6.761905 |
| 14 |
10 |
11.428571 |
| 6 |
10 |
4.904762 |
| 8 |
10 |
4.666667 |
| 10 |
9 |
3.952381 |
| 17 |
9 |
3.809524 |
| 20 |
8 |
4.190476 |
| 4 |
8 |
4.000000 |
| 16 |
8 |
3.428571 |
| 12 |
7 |
3.190476 |
| 5 |
5 |
4.761905 |
| 3 |
5 |
4.476191 |
| 19 |
4 |
4.619048 |
| 15 |
4 |
2.809524 |
| 13 |
4 |
2.714286 |
| 9 |
4 |
2.619048 |
Is it possible that subjects’ network representations might be
reflecting some other centrality metric? In the original paper,
Krackhardt notes that betweenness seems to have some predictive power.
For the 18-21 and 1-7 test cases, we see that betweenness centrality
does make the “correct” prediction about which network member is
represented as being more important. But, we should note that
betweenness doesn’t do the greatest job predicting perceived popularity
across the board; its greatest predictive power is in explaining the
popularity discrepancy for the most popular managers.
centrality_differences %>%
pivot_longer(cols = Degree:Betweenness, names_to = "metric") %>%
ggplot(aes(x=value, y=Perceived)) +
gg +
facet_wrap(~metric, scales = "free_x") +
geom_smooth(method = "lm", se = FALSE) +
geom_label(aes(label = name)) +
scale_x_continuous(name = "True centrality") +
scale_y_continuous(name = "Perceived centrality")
## `geom_smooth()` using formula = 'y ~ x'

centrality_differences %>%
kable()
| 2 |
13.047619 |
18 |
5.9357143 |
| 18 |
11.952381 |
15 |
88.9166667 |
| 21 |
8.380952 |
15 |
60.1269841 |
| 7 |
10.380952 |
13 |
27.6246032 |
| 1 |
5.095238 |
13 |
13.7468254 |
| 11 |
6.761905 |
11 |
1.1984127 |
| 14 |
11.428571 |
10 |
0.5888889 |
| 6 |
4.904762 |
10 |
0.0000000 |
| 8 |
4.666667 |
10 |
3.9746032 |
| 10 |
3.952381 |
9 |
18.2968254 |
| 17 |
3.809524 |
9 |
2.5317460 |
| 20 |
4.190476 |
8 |
7.9793651 |
| 4 |
4.000000 |
8 |
13.7087302 |
| 16 |
3.428571 |
8 |
0.7000000 |
| 12 |
3.190476 |
7 |
0.2539683 |
| 5 |
4.761905 |
5 |
5.0785714 |
| 3 |
4.476191 |
5 |
6.6047619 |
| 19 |
4.619048 |
4 |
0.7539683 |
| 15 |
2.809524 |
4 |
6.1325397 |
| 13 |
2.714286 |
4 |
0.8928571 |
| 9 |
2.619048 |
4 |
3.9539683 |
Simulated observations
We know that an individual’s embedding within a network dictates what
interactions and/or relationships they’re able to observe. Therefore,
when building predicted cognitive maps, we should use a different set of
interactions to inform each subject’s predicted representations. Of
course, we have no idea what individual subjects’ observations actually
are. So we’ll need to come up with a compact and reasonable set of
assumptions about what observations were most likely available to
individual network members.
Here are three key assumptions we’ll make here:
- We’ll assume (trivially) that people can observe interactions
between themselves and their immediate advisors (and/or advisees).
- We’ll also assume that people are generally able to observe
interactions between advisors-of-advisors (and/or advisees-of-advisees),
either through firsthand observation or secondhand chatter.
- Though of course it’s plausible that people might observe more
distant interactions, we’ll assume this happens with enough infrequency
that we can ignore those interactions for the sake of modeling.
We’ve left open an ambiguity in those assumptions: are people
observing advisors-of-advisors, and/or advisees-of-advisees? To aid
understanding, we’ll use the following example. Suppose we’re looking at
a subset of a network consisting of the grad student Abby, who asks the
postdoc Betty for advice; in turn, Betty the postdoc asks Cathy the
assistant professor for advice; and Cathy asks Dani the associate
professor for advice. There are three reasonable ways that observations
might work in this network:
- Observations go “out”: When Abby asks Betty for advice, Betty
responds by sharing the wisdom she’s gained from asking Cathy for
advice. That leads Abby to observe that Betty goes to Cathy for
advice.
- Observations go “in”: Betty has asked Cathy for advice. Cathy thinks
Betty has asked a great question that she doesn’t know the answer to, so
Cathy asks Dani about it. That leads Dani to observe that Betty goes to
Cathy for advice.
- It goes both ways.
We may be able to test this empirically. We would need to simulate a
set of observations consistent with all three possibilities, generate
model predictions from those simulations, then compare how well those
models fit managers’ actual perceptions of the network.
# Observations go both ways
obs_edgelist_all <- expand_grid(
sub_id = 1:21,
# Start with all one-step egocentric observations
krackhardt_egocentric
) %>%
# Convert adjlist into edgelist
filter(edge == 1) %>%
select(-edge) %>%
# For a given node, we want to know who their "advisors-of-advisors" are
# (or equivalently, "advisees-of-advisees")
left_join(
krackhardt_g %>%
mutate(neighbors = local_members(order = 1, mode = "all")) %>%
as_tibble(),
by = c("sub_id" = "name")
) %>%
# We assume that nodes are able to observe (directly or through chatter)
# advice-giving interactions from their advisors and advisors-of-advisors
# (or equivalently, advisees and advisees-of-advisees)
rowwise() %>%
filter((from %in% neighbors) | (to %in% neighbors)) %>%
ungroup() %>%
select(-neighbors) %>%
# Make pretty
arrange(sub_id, from)
# Advisees observe who advises their advisors
obs_edgelist_out <- expand_grid(
sub_id = 1:21,
krackhardt_egocentric
) %>%
filter(edge == 1) %>%
select(-edge) %>%
left_join(
krackhardt_g %>%
mutate(neighbors = local_members(order = 1, mode = "out")) %>%
as_tibble(),
by = c("sub_id" = "name")
) %>%
rowwise() %>%
filter((from %in% neighbors) | (to %in% neighbors)) %>%
ungroup() %>%
select(-neighbors) %>%
arrange(sub_id, from)
# Advisors observe who their advisees advise
obs_edgelist_in <- expand_grid(
sub_id = 1:21,
krackhardt_egocentric
) %>%
filter(edge == 1) %>%
select(-edge) %>%
left_join(
krackhardt_g %>%
mutate(neighbors = local_members(order = 1, mode = "in")) %>%
as_tibble(),
by = c("sub_id" = "name")
) %>%
rowwise() %>%
filter((from %in% neighbors) | (to %in% neighbors)) %>%
ungroup() %>%
select(-neighbors) %>%
arrange(sub_id, from)
obs_adjlist_all <- expand_grid(sub_id = 1:21, from = sub_id, to = sub_id) %>%
left_join(
obs_edgelist_all %>% mutate(edge = 1),
by = c("sub_id", "from", "to")
) %>%
mutate(edge = if_else(is.na(edge), 0, edge))
obs_adjlist_out <- expand_grid(sub_id = 1:21, from = sub_id, to = sub_id) %>%
left_join(
obs_edgelist_out %>% mutate(edge = 1),
by = c("sub_id", "from", "to")
) %>%
mutate(edge = if_else(is.na(edge), 0, edge))
obs_adjlist_in <- expand_grid(sub_id = 1:21, from = sub_id, to = sub_id) %>%
left_join(
obs_edgelist_in %>% mutate(edge = 1),
by = c("sub_id", "from", "to")
) %>%
mutate(edge = if_else(is.na(edge), 0, edge))
Schema-based representation
If people were using triad or community schemas/heuristics to inform
representation, what would this look like? Using literally the exact
same tools that we used to analyze the butterfly network, let’s create
some predicted representations.
schema_experts_all <- obs_adjlist_all %>%
# Memorization
group_by(sub_id, from) %>%
mutate(
mem_value = edge / sum(edge),
mem_value = if_else(is.nan(mem_value), 0, mem_value)
) %>%
ungroup() %>%
# Now triads
left_join(
obs_adjlist_all %>%
group_by(sub_id) %>%
nest() %>%
mutate(triad = map(data, ~build_rep_triad(.x, "edge"))) %>%
unnest(triad) %>%
ungroup() %>%
select(-c(data, transition_scaling)) %>%
mutate(triad_value = if_else(is.nan(triad_value), 0, triad_value)),
by = c("sub_id", "from", "to")
) %>%
# Finally communities
left_join(
obs_adjlist_all %>%
group_by(sub_id) %>%
nest() %>%
mutate(comm = map(data, ~build_rep_community(.x, "edge"))) %>%
unnest(comm) %>%
ungroup() %>%
select(-c(data, transition_scaling)),
by = c("sub_id", "from", "to")
)
schema_experts_out <- obs_adjlist_out %>%
# Memorization
group_by(sub_id, from) %>%
mutate(
mem_value = edge / sum(edge),
mem_value = if_else(is.nan(mem_value), 0, mem_value)
) %>%
ungroup() %>%
# Now triads
left_join(
obs_adjlist_out %>%
group_by(sub_id) %>%
nest() %>%
mutate(triad = map(data, ~build_rep_triad(.x, "edge"))) %>%
unnest(triad) %>%
ungroup() %>%
select(-c(data, transition_scaling)) %>%
mutate(triad_value = if_else(is.nan(triad_value), 0, triad_value)),
by = c("sub_id", "from", "to")
) %>%
# Finally communities
left_join(
obs_adjlist_out %>%
group_by(sub_id) %>%
nest() %>%
mutate(comm = map(data, ~build_rep_community(.x, "edge"))) %>%
unnest(comm) %>%
ungroup() %>%
select(-c(data, transition_scaling)),
by = c("sub_id", "from", "to")
)
schema_experts_in <- obs_adjlist_in %>%
# Memorization
group_by(sub_id, from) %>%
mutate(
mem_value = edge / sum(edge),
mem_value = if_else(is.nan(mem_value), 0, mem_value)
) %>%
ungroup() %>%
# Now triads
left_join(
obs_adjlist_in %>%
group_by(sub_id) %>%
nest() %>%
mutate(triad = map(data, ~build_rep_triad(.x, "edge"))) %>%
unnest(triad) %>%
ungroup() %>%
select(-c(data, transition_scaling)) %>%
mutate(triad_value = if_else(is.nan(triad_value), 0, triad_value)),
by = c("sub_id", "from", "to")
) %>%
# Finally communities
left_join(
obs_adjlist_in %>%
group_by(sub_id) %>%
nest() %>%
mutate(comm = map(data, ~build_rep_community(.x, "edge"))) %>%
unnest(comm) %>%
ungroup() %>%
select(-c(data, transition_scaling)),
by = c("sub_id", "from", "to")
)
plot_mem_all <- plot_representation(schema_experts_all, mem_value) +
ggtitle("Memorization")
plot_triad_all <- plot_representation(schema_experts_all, triad_value) +
ggtitle("Triad Completion")
plot_comm_all <- plot_representation(schema_experts_all, comm_value) +
ggtitle("Community Detection")
plot_schemas_all <- (
plot_choice | plot_mem_all | plot_triad_all | plot_comm_all
) +
plot_annotation(
title = "Observations of advice-giving go both ways",
theme = theme(plot.title = element_text(size = 15, hjust = 0.5))
)
plot_schemas_all

if (knitting) {
ggsave(
here("outputs", "07-krackhardt", "schema_gallery_all.pdf"),
plot_schemas_all,
width = 12, height = 4,
device = cairo_pdf, units = "in", dpi = 300
)
}
plot_mem_out <- plot_representation(schema_experts_out, mem_value) +
ggtitle("Memorization")
plot_triad_out <- plot_representation(schema_experts_out, triad_value) +
ggtitle("Triad Completion")
plot_comm_out <- plot_representation(schema_experts_out, comm_value) +
ggtitle("Community Detection")
plot_schemas_out <- (
plot_choice | plot_mem_out | plot_triad_out | plot_comm_out
) +
plot_annotation(
title = "Advisees observe advisors' advisors",
theme = theme(plot.title = element_text(size = 15, hjust = 0.5))
)
plot_schemas_out

if (knitting) {
ggsave(
here("outputs", "07-krackhardt", "schema_gallery_out.pdf"),
plot_schemas_out,
width = 12, height = 4,
device = cairo_pdf, units = "in", dpi = 300
)
}
plot_mem_in <- plot_representation(schema_experts_in, mem_value) +
ggtitle("Memorization")
plot_triad_in <- plot_representation(schema_experts_in, triad_value) +
ggtitle("Triad Completion")
plot_comm_in <- plot_representation(schema_experts_in, comm_value) +
ggtitle("Community Detection")
plot_schemas_in <- (
plot_choice | plot_mem_in | plot_triad_in | plot_comm_in
) +
plot_annotation(
title = "Advisors observe advisees' advisees",
theme = theme(plot.title = element_text(size = 15, hjust = 0.5))
)
plot_schemas_in

if (knitting) {
ggsave(
here("outputs", "07-krackhardt", "schema_gallery_in.pdf"),
plot_schemas_in,
width = 12, height = 4,
device = cairo_pdf, units = "in", dpi = 300
)
}
At the group-level… schemas make frankly terrible predictions, no
matter what we assume about observations. Note that if a particular
subject is predicted to ask all other managers for advice, the row
associated with that subject will be filled with a value close to
1/20=0.05. So we can see that the triad completion strategy predicts
that most managers are connected, and the community detection strategy
predicts that literally all managers are connected. Neither comes even a
little bit close to the actual allocentric network representation.
Successor repesentation
Let’s say people use multistep relational abstraction to represent
networks, and let’s use the SR to approximate that kind of abstraction.
Using the observations we generated before, let’s create lots of
learning “trials” to train the algorithm.
sr_observations_all <- obs_edgelist_all %>%
# Create simulated "learning trials" to train an asymptotic SR
expand_grid(rep = 1:100) %>%
# Randomize "order of trials" per repetition
group_by(sub_id, rep) %>%
slice_sample(prop = 1) %>%
ungroup()
sr_observations_out <- obs_edgelist_out %>%
expand_grid(rep = 1:100) %>%
group_by(sub_id, rep) %>%
slice_sample(prop = 1) %>%
ungroup()
sr_observations_in <- obs_edgelist_in %>%
expand_grid(rep = 1:100) %>%
group_by(sub_id, rep) %>%
slice_sample(prop = 1) %>%
ungroup()
And now we can use those to build SRs at different scales. We’ll
assume that every subject is using the same successor horizon…
sr_all <- sr_observations_all %>%
expand_grid(gamma = seq(0.1, 0.9, 0.1), .) %>%
group_by(sub_id, gamma) %>%
nest() %>%
mutate(
sr = map2(
.x = data, .y = gamma,
~build_rep_sr(.x, this_alpha = 0.1, this_gamma = .y)
)
) %>%
unnest(sr) %>%
ungroup() %>%
select(-data) %>%
mutate(gamma = gamma * 10) %>%
pivot_wider(
names_from = gamma,
names_prefix = "sr",
values_from = sr_value
)
sr_out <- sr_observations_out %>%
expand_grid(gamma = seq(0.1, 0.9, 0.1), .) %>%
group_by(sub_id, gamma) %>%
nest() %>%
mutate(
sr = map2(
.x = data, .y = gamma,
~build_rep_sr(.x, this_alpha = 0.1, this_gamma = .y)
)
) %>%
unnest(sr) %>%
ungroup() %>%
select(-data) %>%
mutate(gamma = gamma * 10) %>%
pivot_wider(
names_from = gamma,
names_prefix = "sr",
values_from = sr_value
)
sr_in <- sr_observations_in %>%
expand_grid(gamma = seq(0.1, 0.9, 0.1), .) %>%
group_by(sub_id, gamma) %>%
nest() %>%
mutate(
sr = map2(
.x = data, .y = gamma,
~build_rep_sr(.x, this_alpha = 0.1, this_gamma = .y)
)
) %>%
unnest(sr) %>%
ungroup() %>%
select(-data) %>%
mutate(gamma = gamma * 10) %>%
pivot_wider(
names_from = gamma,
names_prefix = "sr",
values_from = sr_value
)
Let’s get a sense for the predictions when the SR is trained on
observations that go both ways.
plot_sr1_all <- sr_all %>%
plot_representation(relation_value = sr1, n_breaks = 4) +
ggtitle("\u03B3 = 0.1")
plot_sr3_all <- sr_all %>%
plot_representation(relation_value = sr3) +
ggtitle("\u03B3 = 0.3")
plot_sr5_all <- sr_all %>%
plot_representation(relation_value = sr5) +
ggtitle("\u03B3 = 0.5")
plot_sr7_all <- sr_all %>%
plot_representation(relation_value = sr7) +
ggtitle("\u03B3 = 0.7")
plot_sr9_all <- sr_all %>%
plot_representation(relation_value = sr9) +
ggtitle("\u03B3 = 0.9")
plot_sr_gallery_all <- (
plot_choice +
plot_sr1_all + plot_sr3_all + plot_sr5_all + plot_sr7_all + plot_sr9_all
)
plot_sr_gallery_all

if (knitting) {
ggsave(
here("outputs", "07-krackhardt", "sr_gallery_all.pdf"),
plot_sr_gallery_all,
width = 12, height = 8,
device = cairo_pdf, units = "in", dpi = 300
)
}
And now where advisees observe their advisors’ advisors…
plot_sr1_out <- sr_out %>%
plot_representation(relation_value = sr1, n_breaks = 4) +
ggtitle("\u03B3 = 0.1")
plot_sr3_out <- sr_out %>%
plot_representation(relation_value = sr3) +
ggtitle("\u03B3 = 0.3")
plot_sr5_out <- sr_out %>%
plot_representation(relation_value = sr5) +
ggtitle("\u03B3 = 0.5")
plot_sr7_out <- sr_out %>%
plot_representation(relation_value = sr7) +
ggtitle("\u03B3 = 0.7")
plot_sr9_out <- sr_out %>%
plot_representation(relation_value = sr9) +
ggtitle("\u03B3 = 0.9")
plot_sr_gallery_out <- (
plot_choice +
plot_sr1_out + plot_sr3_out + plot_sr5_out + plot_sr7_out + plot_sr9_out
)
plot_sr_gallery_out

if (knitting) {
ggsave(
here("outputs", "07-krackhardt", "sr_gallery_out.pdf"),
plot_sr_gallery_out,
width = 12, height = 8,
device = cairo_pdf, units = "in", dpi = 300
)
}
And finally where advisors observe their advisees’ advisees…
plot_sr1_in <- sr_in %>%
plot_representation(relation_value = sr1, n_breaks = 4) +
ggtitle("\u03B3 = 0.1")
plot_sr3_in <- sr_in %>%
plot_representation(relation_value = sr3) +
ggtitle("\u03B3 = 0.3")
plot_sr5_in <- sr_in %>%
plot_representation(relation_value = sr5) +
ggtitle("\u03B3 = 0.5")
plot_sr7_in <- sr_in %>%
plot_representation(relation_value = sr7) +
ggtitle("\u03B3 = 0.7")
plot_sr9_in <- sr_in %>%
plot_representation(relation_value = sr9) +
ggtitle("\u03B3 = 0.9")
plot_sr_gallery_in <- (
plot_choice +
plot_sr1_in + plot_sr3_in + plot_sr5_in + plot_sr7_in + plot_sr9_in
)
plot_sr_gallery_in

if (knitting) {
ggsave(
here("outputs", "07-krackhardt", "sr_gallery_in.pdf"),
plot_sr_gallery_in,
width = 12, height = 8,
device = cairo_pdf, units = "in", dpi = 300
)
}
Statistical tests
Okay, now that we have all of the predicted strategies in hand, we’ll
want to perform some formal statistical tests to verify that the SR is
truly doing the best at explaining subjects’ network representations.
Let’s create a dataframe with all of the info we’ll need.
test_dataset_all <- krackhardt_allocentric %>%
rename(choice = edge) %>%
left_join(schema_experts_all, by = c("sub_id", "from", "to")) %>%
left_join(sr_all, by = c("sub_id", "from", "to"))
test_dataset_out <- krackhardt_allocentric %>%
rename(choice = edge) %>%
left_join(schema_experts_out, by = c("sub_id", "from", "to")) %>%
left_join(sr_out, by = c("sub_id", "from", "to"))
test_dataset_in <- krackhardt_allocentric %>%
rename(choice = edge) %>%
left_join(schema_experts_in, by = c("sub_id", "from", "to")) %>%
left_join(sr_in, by = c("sub_id", "from", "to"))
We’ll do all of the statistical tests for the “observations go both
ways” models. Note that we can’t actually estimate a model for community
detection, as this strategy predicts that everyone is connected to
everyone.
test_mem_all <- test_dataset_all %>%
glmer(
choice ~ mem_value + (1 + mem_value | sub_id),
family = "binomial", data = .
)
test_triad_all <- test_dataset_all %>%
glmer(
choice ~ mem_value + triad_value + (1 + triad_value | sub_id),
family = "binomial", data = .
)
# test_comm_all <- test_dataset_all %>%
# glmer(
# choice ~ mem_value + comm_value + (1 + comm_value | sub_id),
# family = "binomial", data = .
# )
test_sr1_all <- test_dataset_all %>%
glmer(
choice ~ mem_value + sr1 + (1 + sr1 | sub_id),
family = "binomial", data = .
)
test_sr2_all <- test_dataset_all %>%
glmer(
choice ~ mem_value + sr2 + (1 + sr2 | sub_id),
family = "binomial", data = .
)
test_sr3_all <- test_dataset_all %>%
glmer(
choice ~ mem_value + sr3 + (1 + sr3 | sub_id),
family = "binomial", data = .
)
test_sr4_all <- test_dataset_all %>%
glmer(
choice ~ mem_value + sr4 + (1 + sr4 | sub_id),
family = "binomial", data = .
)
test_sr5_all <- test_dataset_all %>%
glmer(
choice ~ mem_value + sr5 + (1 + sr5 | sub_id),
family = "binomial", data = .
)
test_sr6_all <- test_dataset_all %>%
glmer(
choice ~ mem_value + sr6 + (1 + sr6 | sub_id),
family = "binomial", data = .
)
test_sr7_all <- test_dataset_all %>%
glmer(
choice ~ mem_value + sr7 + (1 + sr7 | sub_id),
family = "binomial", data = .
)
test_sr8_all <- test_dataset_all %>%
glmer(
choice ~ mem_value + sr8 + (1 + sr8 | sub_id),
family = "binomial", data = .
)
test_sr9_all <- test_dataset_all %>%
glmer(
choice ~ mem_value + sr9 + (1 + sr9 | sub_id),
family = "binomial", data = .
)
Moving on to the “advisees observe advisors’ advisors” models.
test_mem_out <- test_dataset_out %>%
glmer(
choice ~ mem_value + (1 + mem_value | sub_id),
family = "binomial", data = .
)
test_triad_out <- test_dataset_out %>%
glmer(
choice ~ mem_value + triad_value + (1 + triad_value | sub_id),
family = "binomial", data = .
)
test_comm_out <- test_dataset_out %>%
glmer(
choice ~ mem_value + comm_value + (1 + comm_value | sub_id),
family = "binomial", data = .
)
test_sr1_out <- test_dataset_out %>%
glmer(
choice ~ mem_value + sr1 + (1 + sr1 | sub_id),
family = "binomial", data = .
)
test_sr2_out <- test_dataset_out %>%
glmer(
choice ~ mem_value + sr2 + (1 + sr2 | sub_id),
family = "binomial", data = .
)
test_sr3_out <- test_dataset_out %>%
glmer(
choice ~ mem_value + sr3 + (1 + sr3 | sub_id),
family = "binomial", data = .
)
test_sr4_out <- test_dataset_out %>%
glmer(
choice ~ mem_value + sr4 + (1 + sr4 | sub_id),
family = "binomial", data = .
)
test_sr5_out <- test_dataset_out %>%
glmer(
choice ~ mem_value + sr5 + (1 + sr5 | sub_id),
family = "binomial", data = .
)
test_sr6_out <- test_dataset_out %>%
glmer(
choice ~ mem_value + sr6 + (1 + sr6 | sub_id),
family = "binomial", data = .
)
test_sr7_out <- test_dataset_out %>%
glmer(
choice ~ mem_value + sr7 + (1 + sr7 | sub_id),
family = "binomial", data = .
)
test_sr8_out <- test_dataset_out %>%
glmer(
choice ~ mem_value + sr8 + (1 + sr8 | sub_id),
family = "binomial", data = .
)
test_sr9_out <- test_dataset_out %>%
glmer(
choice ~ mem_value + sr9 + (1 + sr9 | sub_id),
family = "binomial", data = .
)
Finally, the “advisors observe advisees’ advisees” models. Once
again, we can’t estimate a model for community detection, as this
strategy predicts that everyone is connected to everyone.
test_mem_in <- test_dataset_in %>%
glmer(
choice ~ mem_value + (1 + mem_value | sub_id),
family = "binomial", data = .
)
test_triad_in <- test_dataset_in %>%
glmer(
choice ~ mem_value + triad_value + (1 + triad_value | sub_id),
family = "binomial", data = .
)
# test_comm_in <- test_dataset_in %>%
# glmer(
# choice ~ mem_value + comm_value + (1 + comm_value | sub_id),
# family = "binomial", data = .
# )
test_sr1_in <- test_dataset_in %>%
glmer(
choice ~ mem_value + sr1 + (1 + sr1 | sub_id),
family = "binomial", data = .
)
test_sr2_in <- test_dataset_in %>%
glmer(
choice ~ mem_value + sr2 + (1 + sr2 | sub_id),
family = "binomial", data = .
)
test_sr3_in <- test_dataset_in %>%
glmer(
choice ~ mem_value + sr3 + (1 + sr3 | sub_id),
family = "binomial", data = .
)
test_sr4_in <- test_dataset_in %>%
glmer(
choice ~ mem_value + sr4 + (1 + sr4 | sub_id),
family = "binomial", data = .
)
test_sr5_in <- test_dataset_in %>%
glmer(
choice ~ mem_value + sr5 + (1 + sr5 | sub_id),
family = "binomial", data = .
)
test_sr6_in <- test_dataset_in %>%
glmer(
choice ~ mem_value + sr6 + (1 + sr6 | sub_id),
family = "binomial", data = .
)
test_sr7_in <- test_dataset_in %>%
glmer(
choice ~ mem_value + sr7 + (1 + sr7 | sub_id),
family = "binomial", data = .
)
test_sr8_in <- test_dataset_in %>%
glmer(
choice ~ mem_value + sr8 + (1 + sr8 | sub_id),
family = "binomial", data = .
)
test_sr9_in <- test_dataset_in %>%
glmer(
choice ~ mem_value + sr9 + (1 + sr9 | sub_id),
family = "binomial", data = .
)
Of all of these models, which has the “best” fit, based on BIC?
# Which has the best "goodness-of-fit"?
goodness_of_fit <- bind_rows(
# All: goes both ways
glance(test_mem_all) %>% mutate(model = "mem_all"),
glance(test_triad_all) %>% mutate(model = "triad_all"),
glance(test_sr1_all) %>% mutate(model = "sr1_all"),
glance(test_sr2_all) %>% mutate(model = "sr2_all"),
glance(test_sr3_all) %>% mutate(model = "sr3_all"),
glance(test_sr4_all) %>% mutate(model = "sr4_all"),
glance(test_sr5_all) %>% mutate(model = "sr5_all"),
glance(test_sr6_all) %>% mutate(model = "sr6_all"),
glance(test_sr7_all) %>% mutate(model = "sr7_all"),
glance(test_sr8_all) %>% mutate(model = "sr8_all"),
glance(test_sr9_all) %>% mutate(model = "sr9_all"),
# Out: advisors of advisors
glance(test_mem_out) %>% mutate(model = "mem_out"),
glance(test_triad_out) %>% mutate(model = "triad_out"),
glance(test_comm_out) %>% mutate(model = "comm_out"),
glance(test_sr1_out) %>% mutate(model = "sr1_out"),
glance(test_sr2_out) %>% mutate(model = "sr2_out"),
glance(test_sr3_out) %>% mutate(model = "sr3_out"),
glance(test_sr4_out) %>% mutate(model = "sr4_out"),
glance(test_sr5_out) %>% mutate(model = "sr5_out"),
glance(test_sr6_out) %>% mutate(model = "sr6_out"),
glance(test_sr7_out) %>% mutate(model = "sr7_out"),
glance(test_sr8_out) %>% mutate(model = "sr8_out"),
glance(test_sr9_out) %>% mutate(model = "sr9_out"),
# In: advisees of advisees
glance(test_mem_in) %>% mutate(model = "mem_in"),
glance(test_triad_in) %>% mutate(model = "triad_in"),
glance(test_sr1_in) %>% mutate(model = "sr1_in"),
glance(test_sr2_in) %>% mutate(model = "sr2_in"),
glance(test_sr3_in) %>% mutate(model = "sr3_in"),
glance(test_sr4_in) %>% mutate(model = "sr4_in"),
glance(test_sr5_in) %>% mutate(model = "sr5_in"),
glance(test_sr6_in) %>% mutate(model = "sr6_in"),
glance(test_sr7_in) %>% mutate(model = "sr7_in"),
glance(test_sr8_in) %>% mutate(model = "sr8_in"),
glance(test_sr9_in) %>% mutate(model = "sr9_in"),
) %>%
select(model, everything()) %>%
arrange(BIC) %>%
# Make this a little more human-readable
separate(model, into = c("model", "direction")) %>%
mutate(
direction = case_when(
direction == "out" ~ "advisee observes advisor of advisor",
direction == "in" ~ "advisor observes advisee of advisee",
direction == "all" ~ "both ways"
)
)
goodness_of_fit %>%
mutate(
model = fct_relevel(
model,
"sr1", "sr2", "sr3", "sr4", "sr5", "sr6", "sr7", "sr8", "sr9",
"mem", "triad", "comm"
)
) %>%
ggplot(aes(x = model, y = BIC, color = direction)) +
gg +
geom_point() +
ggtitle("Model goodness-of-fit") +
theme(legend.position = "bottom")

goodness_of_fit %>%
kable()
| sr7 |
advisee observes advisor of advisor |
8400 |
1 |
-4363.029 |
8738.058 |
8780.274 |
8565.413 |
8394 |
| sr8 |
advisee observes advisor of advisor |
8400 |
1 |
-4363.853 |
8739.706 |
8781.922 |
8566.508 |
8394 |
| sr6 |
advisee observes advisor of advisor |
8400 |
1 |
-4369.466 |
8750.931 |
8793.147 |
8580.404 |
8394 |
| sr9 |
advisee observes advisor of advisor |
8400 |
1 |
-4375.204 |
8762.408 |
8804.624 |
8592.060 |
8394 |
| sr5 |
advisee observes advisor of advisor |
8400 |
1 |
-4379.140 |
8770.281 |
8812.497 |
8602.266 |
8394 |
| sr4 |
advisee observes advisor of advisor |
8400 |
1 |
-4389.390 |
8790.781 |
8832.996 |
8625.097 |
8394 |
| sr8 |
both ways |
8400 |
1 |
-4398.735 |
8809.469 |
8851.685 |
8657.019 |
8394 |
| sr7 |
both ways |
8400 |
1 |
-4398.873 |
8809.746 |
8851.962 |
8657.895 |
8394 |
| sr3 |
advisee observes advisor of advisor |
8400 |
1 |
-4398.903 |
8809.805 |
8852.021 |
8646.054 |
8394 |
| sr6 |
both ways |
8400 |
1 |
-4403.292 |
8818.583 |
8860.799 |
8668.298 |
8394 |
| sr9 |
both ways |
8400 |
1 |
-4406.178 |
8824.357 |
8866.573 |
8673.713 |
8394 |
| sr2 |
advisee observes advisor of advisor |
8400 |
1 |
-4407.193 |
8826.387 |
8868.603 |
8664.134 |
8394 |
| sr5 |
both ways |
8400 |
1 |
-4409.244 |
8830.487 |
8872.703 |
8681.930 |
8394 |
| sr1 |
advisee observes advisor of advisor |
8400 |
1 |
-4414.189 |
8840.378 |
8882.594 |
8679.243 |
8394 |
| sr4 |
both ways |
8400 |
1 |
-4415.308 |
8842.615 |
8884.831 |
8695.618 |
8394 |
| sr3 |
both ways |
8400 |
1 |
-4420.912 |
8853.824 |
8896.040 |
8708.120 |
8394 |
| triad |
advisee observes advisor of advisor |
8400 |
1 |
-4422.288 |
8856.576 |
8898.791 |
8721.435 |
8394 |
| sr2 |
both ways |
8400 |
1 |
-4425.886 |
8863.773 |
8905.989 |
8719.092 |
8394 |
| sr1 |
both ways |
8400 |
1 |
-4430.221 |
8872.442 |
8914.658 |
8728.545 |
8394 |
| triad |
both ways |
8400 |
1 |
-4431.553 |
8875.106 |
8917.322 |
8740.564 |
8394 |
| mem |
advisee observes advisor of advisor |
8400 |
1 |
-4444.995 |
8899.991 |
8935.171 |
8763.004 |
8395 |
| mem |
both ways |
8400 |
1 |
-4452.356 |
8914.713 |
8949.893 |
8775.496 |
8395 |
| comm |
advisee observes advisor of advisor |
8400 |
1 |
-4461.317 |
8934.634 |
8976.850 |
8821.487 |
8394 |
| mem |
advisor observes advisee of advisee |
8400 |
1 |
-4590.630 |
9191.259 |
9226.439 |
9024.731 |
8395 |
| sr7 |
advisor observes advisee of advisee |
8400 |
1 |
-4591.253 |
9194.506 |
9236.722 |
9021.134 |
8394 |
| triad |
advisor observes advisee of advisee |
8400 |
1 |
-4591.808 |
9195.615 |
9237.831 |
9044.740 |
8394 |
| sr6 |
advisor observes advisee of advisee |
8400 |
1 |
-4591.998 |
9195.997 |
9238.213 |
9024.658 |
8394 |
| sr8 |
advisor observes advisee of advisee |
8400 |
1 |
-4593.417 |
9198.834 |
9241.050 |
9024.487 |
8394 |
| sr5 |
advisor observes advisee of advisee |
8400 |
1 |
-4594.073 |
9200.146 |
9242.362 |
9031.037 |
8394 |
| sr4 |
advisor observes advisee of advisee |
8400 |
1 |
-4596.625 |
9205.251 |
9247.467 |
9038.234 |
8394 |
| sr3 |
advisor observes advisee of advisee |
8400 |
1 |
-4599.254 |
9210.508 |
9252.724 |
9045.352 |
8394 |
| sr9 |
advisor observes advisee of advisee |
8400 |
1 |
-4600.464 |
9212.929 |
9255.145 |
9040.442 |
8394 |
| sr2 |
advisor observes advisee of advisee |
8400 |
1 |
-4601.778 |
9215.556 |
9257.772 |
9052.026 |
8394 |
| sr1 |
advisor observes advisee of advisee |
8400 |
1 |
-4604.117 |
9220.234 |
9262.450 |
9058.124 |
8394 |
Let’s take a look at the best-fitting model estimates:
test_sr7_out %>%
tidy(conf.int = TRUE) %>%
kable()
| fixed |
NA |
(Intercept) |
-1.8725110 |
0.1852784 |
-10.106474 |
0 |
-2.235650 |
-1.509372 |
| fixed |
NA |
mem_value |
3.5286019 |
0.4025315 |
8.766027 |
0 |
2.739655 |
4.317549 |
| fixed |
NA |
sr7 |
14.7453961 |
2.3390595 |
6.303985 |
0 |
10.160924 |
19.329868 |
| ran_pars |
sub_id |
sd__(Intercept) |
0.8095989 |
NA |
NA |
NA |
NA |
NA |
| ran_pars |
sub_id |
cor__(Intercept).sr7 |
-0.2827640 |
NA |
NA |
NA |
NA |
NA |
| ran_pars |
sub_id |
sd__sr7 |
9.5523177 |
NA |
NA |
NA |
NA |
NA |
vif(test_sr7_out)
## mem_value sr7
## 1.081353 1.081353
SR centrality
Can the best-fitting SR explain an individual’s perceptions of other
network members’ centrality?
sr_centrality <- sr_out %>%
# SR centrality from best variant
filter(from != to) %>%
group_by(sub_id, node_id = to) %>%
summarise(sr_centrality = mean(sr7), .groups = "drop") %>%
# Perceived centrality
left_join(
krackhardt_allocentric %>%
group_by(sub_id, node_id = to) %>%
summarise(perceived_centrality = mean(edge), .groups = "drop"),
by = c("sub_id", "node_id")
)
To answer this, we’ll do a random-effects analysis where we take each
individual’s idiosyncratic mental representation of their network, then
rank-correlate it with the SR’s individual-level predictions.
sr_centrality_corr <- sr_centrality %>%
group_by(sub_id) %>%
nest() %>%
mutate(
spearman = map_dbl(
.x = data,
.f = ~with(
.x, cor(sr_centrality, perceived_centrality, method = "spearman")
)
)
) %>%
ungroup() %>%
select(-data)
sr_centrality_corr %>%
mutate(spearman = atanh(spearman)) %>%
select(spearman) %>%
deframe() %>%
t.test() %>%
tidy() %>%
kable(
caption = str_c(
"t-test of the average Spearman correlation between perceived and ",
"SR-predicted centrality (z-transformed)"
)
)
t-test of the average Spearman correlation between perceived
and SR-predicted centrality (z-transformed)
| 0.472048 |
10.55384 |
0 |
20 |
0.3787478 |
0.5653482 |
One Sample t-test |
two.sided |
sr_centrality_corr %>%
summarise(mean_spearman = mean(spearman)) %>%
kable()
Let’s try to visualize these results in an intuitive format.
plot_sr_centrality_group <- sr_centrality %>%
# Get each subject's rank-ordered perceived and SR-predicted centrality
group_by(sub_id) %>%
mutate(across(ends_with("_centrality"), ~rank(.x, ties.method = "min"))) %>%
ungroup() %>%
# Average across subjects to get group-level results
group_by(node_id) %>%
summarise(across(ends_with("_centrality"), mean)) %>%
# For color-coding two pairs of managers with equivalent degree centrality,
# but different perceived centrality
mutate(
colorcode = case_when(
node_id %in% c(1, 7) ~ "a",
node_id %in% c(18, 21) ~ "b"
)
) %>%
ggplot(aes(x=perceived_centrality, y=sr_centrality)) +
gg +
geom_smooth(method = "lm", se = FALSE, color = "black") +
geom_label(aes(label = node_id, fill = colorcode), show.legend = FALSE) +
scale_fill_manual(values = c("#a6cee3", "#b2df8a"), na.value = "grey95") +
scale_x_continuous(name = "Perceived centrality (rank-ordered)") +
scale_y_continuous(name = "SR centrality (rank-ordered)") +
ggtitle("Perceived vs Successor Centrality (Group-Level)")
plot_sr_centrality_group
## `geom_smooth()` using formula = 'y ~ x'

plot_sr_centrality_individual <- sr_centrality %>%
# Get each subject's rank-ordered perceived and SR-predicted centrality
group_by(sub_id) %>%
mutate(across(ends_with("_centrality"), ~rank(.x, ties.method = "min"))) %>%
ungroup() %>%
# Formatting for plotting
pivot_longer(
ends_with("_centrality"),
names_to = "metric",
values_to = "centrality"
) %>%
mutate(
node_id = factor(node_id),
sub_id = str_pad(sub_id, width = 2, side = "left", pad = "0"),
sub_id = str_c("Manager ", sub_id)
) %>%
ggplot(aes(x=node_id, y=centrality, fill=metric)) +
facet_wrap(~sub_id, nrow = 3) +
geom_col(position = "identity", color = "black", alpha = 0.5) +
coord_polar() +
scale_fill_viridis_d(
name = "Centrality",
labels = c("Perceived (Empirical)", "Successor Representation (Simulated)")
) +
ggtitle("Perceived vs Successor Centrality (Individual-Level)") +
theme_bw() +
theme(
plot.title = element_text(hjust = 0.5, size = 13),
plot.subtitle = element_text(hjust = 0.5, size = 11),
panel.grid.minor = element_blank(),
panel.spacing = unit(0.75, "lines"),
legend.box.spacing = unit(0.5, "lines"),
legend.margin = margin(c(0, 0, 0, 0), unit = "lines"),
legend.position = "bottom",
axis.title.x = element_blank(),
axis.title.y = element_blank(),
axis.text.y = element_blank(),
axis.ticks.y = element_blank()
)
plot_sr_centrality_individual

if (knitting) {
ggsave(
here("outputs", "07-krackhardt", "sr_centrality_individual_standard.pdf"),
plot = plot_sr_centrality_individual,
width = 12, height = 8,
device = cairo_pdf, units = "in", dpi = 300
)
}
We’re particularly interested in the manager pairs 1-7 and 18-21. On
an individual-by-individual basis, does the model correctly predict, in
each pair, which manager is represented as being more central? We’ll do
a prevalence test to see whether the model made correct predictions for
significantly greater than 50% of subjects.
sr_centrality %>%
# Find and retain only relevant node-pairs
mutate(
pair_id = case_when(
node_id %in% c(1, 7) ~ "1-7",
node_id %in% c(18, 21) ~ "18-21"
)
) %>%
drop_na() %>%
# Whichever manager is represented as being more central in each node-pair,
# does the model make a correct prediction?
group_by(sub_id, pair_id) %>%
mutate(
across(
c(sr_centrality, perceived_centrality),
~.x - first(.x)
)
) %>%
filter(node_id %in% c(7, 21)) %>%
summarise(
correct = sr_centrality * perceived_centrality > 0,
.groups = "drop"
) %>%
# Tally correct predictions
count(pair_id, correct) %>%
# Prevalence test
filter(correct) %>%
split(.$pair_id) %>%
map_dfr(
.f = ~.x %>%
select(n) %>%
deframe() %>%
binom.test(x = ., n = 21, p = 0.5, alternative = "greater") %>%
tidy(),
.id = "pair_id"
) %>%
kable(caption = "Prevalence test (> 50%)")
Prevalence test (> 50%)
| 1-7 |
0.7142857 |
15 |
0.0391769 |
21 |
0.5126112 |
1 |
Exact binomial test |
greater |
| 18-21 |
0.8571429 |
18 |
0.0007448 |
21 |
0.6707890 |
1 |
Exact binomial test |
greater |
We’d previously noted that betweenness seems to track discrepancies
between a manager’s true versus perceived centrality. Does SR centrality
track with betweenness? The loess curve suggests the relationship is
nonlinear, but there is a strongly significant rank correlation between
the two.
sr_centrality %>%
group_by(name = node_id) %>%
summarise(sr_centrality = mean(sr_centrality)) %>%
left_join(centrality_differences) %>%
ggplot(aes(x=sr_centrality, y=Betweenness)) +
gg +
geom_smooth(method = "loess", se = FALSE) +
geom_label(aes(label = name)) +
xlab("Successor Representation \u03B3 = 0.7")
## Joining with `by = join_by(name)`
## `geom_smooth()` using formula = 'y ~ x'

if (knitting) {
ggsave(
here("outputs", "07-krackhardt", "centrality_sr_vs_betweenness.pdf"),
width = 6, height = 4,
device = cairo_pdf, units = "in", dpi = 300
)
}
## `geom_smooth()` using formula = 'y ~ x'
sr_centrality %>%
group_by(name = node_id) %>%
summarise(sr_centrality = mean(sr_centrality)) %>%
left_join(centrality_differences) %>%
with(cor.test(Betweenness, sr_centrality, method = "spearman", exact = FALSE)) %>%
tidy() %>%
kable(caption = "Betweenness vs SR gamma 0.7")
## Joining with `by = join_by(name)`
Betweenness vs SR gamma 0.7
| 0.8948052 |
162 |
0 |
Spearman’s rank correlation rho |
two.sided |
Company leadership
So far, we have not provided the model with any privileged knowledge
about the company’s senior leadership hierarchy. Yet, using observations
constrained by the network structure, the model has identified most of
the company’s leadership anyways.
The CEO is coded as node 7, and the four Vice Presidents are coded as
2, 14, 18, and 21. We see clear evidence that the model identifies nodes
2, 7, 18, and 21 as being central figures, but the model makes
conspicuously incorrect predictions about manager 14.
Could the model in principle do a better job at identifying manager
14 as a central network member? To test this, we’ll make one additional
assumption about managers’ observations: they observe the senior
leadership twice as much as other network members.
sr_observations_leadership <- obs_edgelist_out %>%
# Double-count CEO and VPs
bind_rows(
obs_edgelist_out %>%
filter(from %in% c(2, 7, 14, 18, 21) | to %in% c(2, 7, 14, 18, 21))
) %>%
expand_grid(rep = 1:100) %>%
group_by(sub_id, rep) %>%
slice_sample(prop = 1) %>%
ungroup()
sr_leadership <- sr_observations_leadership %>%
expand_grid(gamma = seq(0.1, 0.9, 0.1), .) %>%
group_by(sub_id, gamma) %>%
nest() %>%
mutate(
sr = map2(
.x = data, .y = gamma,
~build_rep_sr(.x, this_alpha = 0.1, this_gamma = .y)
)
) %>%
unnest(sr) %>%
ungroup() %>%
select(-data) %>%
mutate(gamma = gamma * 10) %>%
pivot_wider(
names_from = gamma,
names_prefix = "sr",
values_from = sr_value
)
We’ll test whether the model goodness-of-fit is better at \(\gamma = 0.7\), which was the best-fitting
model from before:
test_sr7_leadership <- krackhardt_allocentric %>%
rename(choice = edge) %>%
left_join(schema_experts_out, by = c("sub_id", "from", "to")) %>%
left_join(sr_leadership, by = c("sub_id", "from", "to")) %>%
glmer(
choice ~ mem_value + sr7 + (1 + sr7 | sub_id),
family = "binomial", data = .
)
bind_rows(
glance(test_sr7_out) %>% mutate(model = "sr7 standard"),
glance(test_sr7_leadership) %>% mutate(model = "sr7 leadership 2x")
) %>%
kable()
| 8400 |
1 |
-4363.029 |
8738.058 |
8780.274 |
8565.413 |
8394 |
sr7 standard |
| 8400 |
1 |
-4301.586 |
8615.172 |
8657.388 |
8443.772 |
8394 |
sr7 leadership 2x |
sr_centrality_leadership <- sr_leadership %>%
# SR centrality from best variant
filter(from != to) %>%
group_by(sub_id, node_id = to) %>%
summarise(sr_centrality = mean(sr7), .groups = "drop") %>%
# Perceived centrality
left_join(
krackhardt_allocentric %>%
group_by(sub_id, node_id = to) %>%
summarise(perceived_centrality = mean(edge), .groups = "drop"),
by = c("sub_id", "node_id")
)
sr_centrality_corr_leadership <- sr_centrality_leadership %>%
group_by(sub_id) %>%
nest() %>%
mutate(
spearman = map_dbl(
.x = data,
.f = ~with(
.x, cor(
sr_centrality, perceived_centrality, method = "spearman"
)
)
)
) %>%
ungroup() %>%
select(-data)
sr_centrality_corr_leadership %>%
mutate(spearman = atanh(spearman)) %>%
select(spearman) %>%
deframe() %>%
t.test() %>%
tidy() %>%
kable(
caption = str_c(
"t-test of the average Spearman correlation between perceived and ",
"SR-predicted centrality (z-transformed)"
)
)
t-test of the average Spearman correlation between perceived
and SR-predicted centrality (z-transformed)
| 0.5811331 |
11.88074 |
0 |
20 |
0.4791005 |
0.6831656 |
One Sample t-test |
two.sided |
sr_centrality_corr_leadership %>%
summarise(mean_spearman = mean(spearman)) %>%
kable()
plot_sr_centrality_group_leadership <- sr_centrality_leadership %>%
# Get each subject's rank-ordered perceived and SR-predicted centrality
group_by(sub_id) %>%
mutate(across(ends_with("_centrality"), ~rank(.x, ties.method = "min"))) %>%
ungroup() %>%
# Average across subjects to get group-level results
group_by(node_id) %>%
summarise(across(ends_with("_centrality"), mean)) %>%
# For color-coding two pairs of managers with equivalent degree centrality,
# but different perceived centrality
mutate(
colorcode = case_when(
node_id %in% c(1, 7) ~ "a",
node_id %in% c(18, 21) ~ "b"
)
) %>%
ggplot(aes(x=perceived_centrality, y=sr_centrality)) +
gg +
geom_smooth(method = "lm", se = FALSE, color = "black") +
geom_label(aes(label = node_id, fill = colorcode), show.legend = FALSE) +
scale_fill_manual(values = c("#a6cee3", "#b2df8a"), na.value = "grey95") +
scale_x_continuous(name = "Perceived centrality (rank-ordered)") +
scale_y_continuous(name = "SR centrality (rank-ordered)") +
ggtitle("Perceived vs Successor Centrality (Group-Level)")
plot_sr_centrality_group_leadership
## `geom_smooth()` using formula = 'y ~ x'

plot_sr_centrality_individual_leadership <- sr_centrality_leadership %>%
# Get each subject's rank-ordered perceived and SR-predicted centrality
group_by(sub_id) %>%
mutate(across(ends_with("_centrality"), ~rank(.x, ties.method = "min"))) %>%
ungroup() %>%
# Formatting for plotting
pivot_longer(
ends_with("_centrality"),
names_to = "metric",
values_to = "centrality"
) %>%
mutate(
node_id = factor(node_id),
sub_id = str_pad(sub_id, width = 2, side = "left", pad = "0"),
sub_id = str_c("Manager ", sub_id)
) %>%
ggplot(aes(x=node_id, y=centrality, fill=metric)) +
facet_wrap(~sub_id, nrow = 3) +
geom_col(position = "identity", color = "black", alpha = 0.5) +
coord_polar() +
scale_fill_viridis_d(
name = "Centrality",
labels = c("Perceived (Empirical)", "Successor Representation (Simulated)")
) +
ggtitle("Perceived vs Successor Centrality (Individual-Level)") +
theme_bw() +
theme(
plot.title = element_text(hjust = 0.5, size = 13),
plot.subtitle = element_text(hjust = 0.5, size = 11),
panel.grid.minor = element_blank(),
panel.spacing = unit(0.75, "lines"),
legend.box.spacing = unit(0.5, "lines"),
legend.margin = margin(c(0, 0, 0, 0), unit = "lines"),
legend.position = "bottom",
axis.title.x = element_blank(),
axis.title.y = element_blank(),
axis.text.y = element_blank(),
axis.ticks.y = element_blank()
)
plot_sr_centrality_individual_leadership

if (knitting) {
ggsave(
here("outputs", "07-krackhardt", "sr_centrality_group_leadership.pdf"),
plot = plot_sr_centrality_group_leadership,
width = 6, height = 4,
device = cairo_pdf, units = "in", dpi = 300
)
ggsave(
here("outputs", "07-krackhardt", "sr_centrality_individual_leadership.pdf"),
plot = plot_sr_centrality_individual_leadership,
width = 12, height = 8,
device = cairo_pdf, units = "in", dpi = 300
)
}
## `geom_smooth()` using formula = 'y ~ x'
Figures for paper
network_for_paper <- krackhardt_g %>%
mutate(
Degree = centrality_degree(mode = "in"),
node_colorcode = case_when(
name %in% c(1, 7) ~ "a",
name %in% c(18, 21) ~ "b"
)
) %>%
# To clean up some of the overplotting
activate("edges") %>%
mutate(
edge_colorcode = case_when(
from %in% c(1, 7) | to %in% c(1, 7) ~ "a",
from %in% c(18, 21) | to %in% c(18, 21) ~ "b"
)
) %>%
# Plot the "ground truth" network
ggraph(layout = "stress") +
geom_edge_link(
aes(
start_cap = label_rect(node1.name, padding = margin(15, 15, 15, 15)),
end_cap = label_rect(node2.name, padding = margin(15, 15, 15, 15)),
color = edge_colorcode
),
arrow = arrow(length = unit(5, "pt"), type = "closed"),
show.legend = FALSE
) +
geom_node_label(
aes(label = name, size = Degree, fill = node_colorcode),
show.legend = FALSE
) +
scale_size(range = c(3, 10)) +
scale_fill_manual(values = c("#a6cee3", "#b2df8a"), na.value = "grey95") +
scale_edge_color_manual(
values = c("#1f78b4", "#33a02c"), na.value = "grey80"
) +
ggtitle("Advice Network (Krackhardt 1987)") +
theme(
panel.background = element_blank(),
strip.background = element_blank(),
panel.border = element_blank(),
axis.title = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
plot.title = element_text(hjust = 0.5, size = 13),
strip.text = element_text(hjust = 0.5, size = 13),
legend.position = "bottom"
)
network_for_paper

if (knitting) {
ggsave(
here("outputs", "07-krackhardt", "network_graph.pdf"),
plot = network_for_paper,
width = 12, height = 5,
device = cairo_pdf, units = "in", dpi = 300
)
}
representation_for_paper <- (
(plot_choice + ggtitle("Perceived (Empirical)")) |
plot_sr7_out + ggtitle("Successor Rep. \u03B3 = 0.7 (Simulated)")
) +
plot_annotation(
title = "Network Representation",
theme = theme(plot.title = element_text(size = 13, hjust = 0.5))
)
representation_for_paper

if (knitting) {
ggsave(
here("outputs", "07-krackhardt", "representation.pdf"),
plot = representation_for_paper,
width = 12, height = 5,
device = cairo_pdf, units = "in", dpi = 300
)
}
centrality_individual_for_paper <- sr_centrality %>%
filter(sub_id %in% c(17, 19)) %>%
# Get each subject's rank-ordered perceived and SR-predicted centrality
group_by(sub_id) %>%
mutate(across(ends_with("_centrality"), ~rank(.x, ties.method = "min"))) %>%
ungroup() %>%
# Formatting for plotting
pivot_longer(
ends_with("_centrality"),
names_to = "metric",
values_to = "centrality"
) %>%
mutate(
node_id = factor(node_id),
sub_id = str_pad(sub_id, width = 2, side = "left", pad = "0"),
sub_id = str_c("Manager ", sub_id)
) %>%
ggplot(aes(x=node_id, y=centrality, fill=metric)) +
facet_wrap(~sub_id) +
geom_col(position = "identity", color = "black", alpha = 0.5) +
coord_polar() +
scale_fill_viridis_d(
name = "Centrality",
labels = c("Perceived (Empirical)", "Successor Rep. (Simulated)")
) +
ggtitle("Individual-Level") +
theme_bw() +
theme(
plot.title = element_text(hjust = 0.5, size = 13),
plot.subtitle = element_text(hjust = 0.5, size = 11),
panel.grid.minor = element_blank(),
panel.spacing = unit(0.75, "lines"),
legend.box.spacing = unit(0.5, "lines"),
legend.margin = margin(c(0, 0, 0, 0), unit = "lines"),
legend.position = "bottom",
axis.title.x = element_blank(),
axis.title.y = element_blank(),
axis.text.y = element_blank(),
axis.ticks.y = element_blank()
)
centrality_for_paper <- (
(
plot_sr_centrality_group +
ggtitle("Group-Level") +
scale_y_continuous(name = "Successor Rep. centrality (rank-ordered)")
) |
centrality_individual_for_paper
) +
plot_annotation(
title = "Perceived vs Successor Centrality",
theme = theme(plot.title = element_text(size = 13, hjust = 0.5))
)
## Scale for y is already present.
## Adding another scale for y, which will replace the existing scale.
centrality_for_paper
## `geom_smooth()` using formula = 'y ~ x'

if (knitting) {
ggsave(
here("outputs", "07-krackhardt", "centrality.pdf"),
plot = centrality_for_paper,
width = 12, height = 5,
device = cairo_pdf, units = "in", dpi = 300
)
}
## `geom_smooth()` using formula = 'y ~ x'
Save data
It was a bit of a pain getting the raw data into shape, so we’ll save
the cleaned versions for posterity.
if (knitting) {
krackhardt_egocentric %>%
write_csv(here("data", "krackhardt", "clean_egocentric.csv"))
krackhardt_allocentric %>%
rename(choice = edge) %>%
write_csv(here("data", "krackhardt", "clean_allocentric.csv"))
}
Session info
sessionInfo()
## R version 4.3.1 (2023-06-16)
## Platform: aarch64-apple-darwin20 (64-bit)
## Running under: macOS Ventura 13.6.1
##
## Matrix products: default
## BLAS: /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRblas.0.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRlapack.dylib; LAPACK version 3.11.0
##
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
##
## time zone: America/New_York
## tzcode source: internal
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] broom.mixed_0.2.9.4 lmerTest_3.1-3 lme4_1.1-34
## [4] Matrix_1.6-1 patchwork_1.1.3 ggraph_2.1.0
## [7] tidygraph_1.2.3 here_1.0.1 lubridate_1.9.2
## [10] forcats_1.0.0 stringr_1.5.0 dplyr_1.1.2
## [13] purrr_1.0.2 readr_2.1.4 tidyr_1.3.0
## [16] tibble_3.2.1 ggplot2_3.4.3 tidyverse_2.0.0
##
## loaded via a namespace (and not attached):
## [1] tidyselect_1.2.0 viridisLite_0.4.2 farver_2.1.1
## [4] viridis_0.6.4 fastmap_1.1.1 tweenr_2.0.2
## [7] digest_0.6.33 timechange_0.2.0 lifecycle_1.0.3
## [10] magrittr_2.0.3 compiler_4.3.1 rlang_1.1.1
## [13] sass_0.4.7 tools_4.3.1 igraph_1.5.1
## [16] utf8_1.2.3 yaml_2.3.7 knitr_1.43
## [19] labeling_0.4.2 graphlayouts_1.0.0 bit_4.0.5
## [22] abind_1.4-5 withr_2.5.0 numDeriv_2016.8-1.1
## [25] grid_4.3.1 polyclip_1.10-4 fansi_1.0.4
## [28] colorspace_2.1-0 future_1.33.0 globals_0.16.2
## [31] scales_1.2.1 MASS_7.3-60 cli_3.6.1
## [34] crayon_1.5.2 rmarkdown_2.24 generics_0.1.3
## [37] tzdb_0.4.0 minqa_1.2.5 cachem_1.0.8
## [40] ggforce_0.4.1 splines_4.3.1 parallel_4.3.1
## [43] vctrs_0.6.3 boot_1.3-28.1 jsonlite_1.8.7
## [46] carData_3.0-5 car_3.1-2 hms_1.1.3
## [49] bit64_4.0.5 ggrepel_0.9.3 listenv_0.9.0
## [52] jquerylib_0.1.4 glue_1.6.2 parallelly_1.36.0
## [55] nloptr_2.0.3 codetools_0.2-19 stringi_1.7.12
## [58] gtable_0.3.3 munsell_0.5.0 pillar_1.9.0
## [61] furrr_0.3.1 htmltools_0.5.6 R6_2.5.1
## [64] rprojroot_2.0.3 vroom_1.6.3 evaluate_0.21
## [67] lattice_0.21-8 highr_0.10 backports_1.4.1
## [70] broom_1.0.5 bslib_0.5.1 Rcpp_1.0.11
## [73] gridExtra_2.3 nlme_3.1-162 mgcv_1.8-42
## [76] xfun_0.40 fs_1.6.3 pkgconfig_2.0.3
LS0tCnRpdGxlOiAiUmVhbmFseXplIEtyYWNraGFyZHQgMTk4NyIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IHRydWUKLS0tCgpJbiBoaXMgMTk4NyBwYXBlciAoQ29nbml0aXZlIFNvY2lhbCBTdHJ1Y3R1cmVzKSwgS3JhY2toYXJkdCBpbmNsdWRlcyBkYXRhIGZyb20gYSAyMS1tZW1iZXIgbmV0d29yayBvZiBtYW5hZ2VycyAoYWxsIG1hbGUpIGF0IGEgdGVjaCBtYW51ZmFjdHVyaW5nIGNvbXBhbnkuIFRoZXNlIGRhdGEgaW5jbHVkZSBub3Qgb25seSBlZ29jZW50cmljIHJlcG9ydHMgKHRoZXNlIGFyZSB0aGUgcGVvcGxlICpJKiBnbyB0byBmb3IgYWR2aWNlKSwgYnV0IGFsc28gYWxsb2NlbnRyaWMgcmVwb3J0cyAoSSB0aGluayBKb2huIG9mdGVuIGFza3MgQmlsbCBmb3IgYWR2aWNlKS4gV2UgY2FuIHRyeSB0ZXN0aW5nIHdoZXRoZXIgbXVsdGlzdGVwIHJlbGF0aW9uYWwgYWJzdHJhY3Rpb24gZXhwbGFpbnMgdGhlIHN1YmplY3RzJyBhbGxvY2VudHJpYyBiZWxpZWZzIGluIHRoaXMgZGF0YXNldC4KCiMgU2V0dXAKCmBgYHtyIHNldHVwfQojIFNldCBhIHJhbmRvbSBzZWVkIGZvciByZXByb2R1Y2liaWxpdHkKc2V0LnNlZWQoc3VtKHV0ZjhUb0ludCgia3JhY2toYXJkdCIpKSkKCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGhlcmUpCmxpYnJhcnkodGlkeWdyYXBoKQpsaWJyYXJ5KGdncmFwaCkKbGlicmFyeShwYXRjaHdvcmspCmxpYnJhcnkobG1lNCkKbGlicmFyeShsbWVyVGVzdCkKbGlicmFyeShicm9vbS5taXhlZCkKCmthYmxlIDwtIGtuaXRyOjprYWJsZQp2aWYgPC0gY2FyOjp2aWYKCmtuaXR0aW5nIDwtIGtuaXRyOjppc19odG1sX291dHB1dCgpCgppZiAoa25pdHRpbmcpIHsKICAjIENyZWF0ZSBkaXJlY3RvcmllcyBmb3Igc2F2aW5nIHN0dWZmCiAgaWYgKCFkaXIuZXhpc3RzKGhlcmUoIm91dHB1dHMiKSkpIHsKICAgIGRpci5jcmVhdGUoaGVyZSgib3V0cHV0cyIpKQogIH0KICAKICBpZiAoIWRpci5leGlzdHMoaGVyZSgib3V0cHV0cyIsICIwNy1rcmFja2hhcmR0IikpKSB7CiAgICBkaXIuY3JlYXRlKGhlcmUoIm91dHB1dHMiLCAiMDcta3JhY2toYXJkdCIpKQogIH0KfQoKIyBQdWxsIGluIHNvbWUgbW9kZWxpbmcgdG9vbHMKc291cmNlKGhlcmUoImNvZGUiLCAidXRpbHMiLCAicmVwcmVzZW50YXRpb25fdXRpbHMuUiIpKQpzb3VyY2UoaGVyZSgiY29kZSIsICJ1dGlscyIsICJuZXR3b3JrX3V0aWxzLlIiKSkKCmdnIDwtIGxpc3QoCiAgdGhlbWVfYncoKSwKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxMyksCiAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTEpLAogICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5zcGFjaW5nID0gdW5pdCgwLjc1LCAibGluZXMiKSwKICAgIGxlZ2VuZC5ib3guc3BhY2luZyA9IHVuaXQoMC41LCAibGluZXMiKSwKICAgIGxlZ2VuZC5tYXJnaW4gPSBtYXJnaW4oYygwLCAwLCAwLCAwKSwgdW5pdCA9ICJsaW5lcyIpCiAgKQopCgpwbG90X3JlcHJlc2VudGF0aW9uIDwtIGZ1bmN0aW9uKHJlcF9kZiwgcmVsYXRpb25fdmFsdWUsIG5fYnJlYWtzID0gMykgewogIHBsb3RfZGYgPC0gcmVwX2RmICU+JQogICAgZmlsdGVyKGZyb20gIT0gdG8pICU+JQogICAgZ3JvdXBfYnkoZnJvbSwgdG8pICU+JQogICAgc3VtbWFyaXNlKHZhbHVlID0gbWVhbih7e3JlbGF0aW9uX3ZhbHVlfX0pLCAuZ3JvdXBzID0gImRyb3AiKQogIAogIHBsb3RfZGYgJT4lCiAgICAjIFBsb3QKICAgIG11dGF0ZSgKICAgICAgYWNyb3NzKGMoZnJvbSwgdG8pLCBmYWN0b3IpLAogICAgICBmcm9tID0gZmN0X3Jldihmcm9tKQogICAgKSAlPiUKICAgIGdncGxvdChhZXMoeD10bywgeT1mcm9tLCBmaWxsPXZhbHVlKSkgKwogICAgZ2cgKwogICAgZ2VvbV90aWxlKCkgKwogICAgY29vcmRfZml4ZWQoKSArCiAgICBzY2FsZV9maWxsX3ZpcmlkaXNfYygKICAgICAgb3B0aW9uID0gIm1hZ21hIiwgbmFtZSA9IE5VTEwsIG5hLnZhbHVlID0gIndoaXRlIiwgbi5icmVha3MgPSBuX2JyZWFrcwogICAgKSArCiAgICB0aGVtZSgKICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdCA9IDEpCiAgICApCn0KCmNoZWNrX3NpZ25pZmljYW5jZSA8LSBmdW5jdGlvbih0aWR5X3N0YXRzKSB7CiAgdGlkeV9zdGF0cyAlPiUKICAgIG11dGF0ZSgKICAgICAgc2lnbmlmaWNhbmNlID0gY2FzZV93aGVuKAogICAgICAgIHAudmFsdWUgPCAwLjAwMSB+ICIqKioiLAogICAgICAgIHAudmFsdWUgPCAwLjAxIH4gIioqIiwKICAgICAgICBwLnZhbHVlIDwgMC4wNSB+ICIqIiwKICAgICAgICBwLnZhbHVlIDwgMC4xIH4gIi4iLAogICAgICAgIFRSVUUgfiAiIgogICAgICApCiAgICApCn0KYGBgCgpUaGVzZSBkYXRhIGFyZSBpbmNsdWRlZCBpbiBLcmFja2hhcmR0IDE5ODcsIEFwcGVuZGl4IEEuIEVhY2ggYWxsb2NlbnRyaWMgQ1NWIGNvbnRhaW5zIGFuIGFkamFjZW5jeSBtYXRyaXgsIHNvIHdlJ2xsIG5lZWQgdG8gZG8gYSBsaXR0bGUgd29yayB0byBnZXQgdGhlbSBpbnRvIGEgdGlkeS1mcmllbmRseSBmb3JtYXQuCgpUaGUgImVnb2NlbnRyaWMiIG5ldHdvcmsgaXMgZGVmaW5lZCBpbiB0aGUgd2F5IHRoYXQgc29jaWFsIG5ldHdvcmtzIGFyZSBtb3N0IG9mdGVuIGRlZmluZWQ6IGJhc2VkIG9uIGVhY2ggc3ViamVjdCdzIGFuc3dlciB0byB0aGUgcXVlc3Rpb24sICJXaG8gYXJlIHlvdSBjb25uZWN0ZWQgdG8/IiBPZnRlbnRpbWVzLCB0aGlzIHF1ZXN0aW9uIGlzIHBocmFzZWQgdG8gbWVhc3VyZSBmcmllbmRzaGlwcyAoZS5nLiwgIkFyZSB5b3UgZnJpZW5kcyB3aXRoIFg/IikuIEluIHRoaXMgcGFydGljdWxhciBkYXRhc2V0LCB0aGUgcXVlc3Rpb24gaXMgc29tZXRoaW5nIGNsb3NlciB0byAiV2hvIGRvIHlvdSBhc2sgZm9yIGFkdmljZT8iCgpUaGUgImFsbG9jZW50cmljIiBjb2duaXRpdmUgbWFwcyBtZWFzdXJlIGVhY2ggc3ViamVjdCdzIGFuc3dlciB0byB0aGUgcXVlc3Rpb24sICJEb2VzIFggYXNrIFkgZm9yIGFkdmljZT8iIFRoaXMgaW5jbHVkZXMgdGhlIHNwZWNpYWwgY2FzZSBvZiwgIkRvZXMgWCBhc2sgeW91IGZvciBhZHZpY2U/IiBIZXJlJ3MgdGhlIHJhdGlvbmFsZSBmb3IgaW5jbHVkaW5nIHRoZSBzcGVjaWFsIGNhc2UgaW4gYWxsb2NlbnRyaWMgbWFwcy4gSW1hZ2luZSBmb3IgYSBtb21lbnQgdGhhdCB0aGlzIHdlcmUgYSBzdHVkeSBhYm91dCBmcmllbmRzaGlwcyBpbnN0ZWFkIG9mIGFkdmljZS1naXZpbmcuIEluIHRoYXQgY2FzZSwgd2Ugd291bGQgY29uc2lkZXIgIkFyZSB5b3UgZnJpZW5kcyB3aXRoIFg/IiB0byBiZSBhIHF1ZXN0aW9uIHRoYXQgc3ViamVjdHMgd291bGQga25vdyB0aGUgYW5zd2VyIHRvIChvciBhdCBsZWFzdCwgdGhleSB3b3VsZCBrbm93IGJldHRlciB0aGFuIGFueW9uZSBlbHNlKS4gT24gdGhlIG90aGVyIGhhbmQsIHdlIHdvdWxkIGNvbnNpZGVyIHRoZSBxdWVzdGlvbiAiRG9lcyBYIGNvbnNpZGVyIHlvdSBhIGZyaWVuZD8iIHRvIGJlIG1vcmUgb2YgYW4gaW5mZXJlbmNlIHRoYW4ga25vd2xlZGdlLiBJIGRvbid0IGtub3cgd2hldGhlciBYIGNvbnNpZGVycyBtZSBhIGZyaWVuZDsgSSBkb24ndCBjb25zaWRlciBYIHRvIGJlIGEgZnJpZW5kLCBidXQgd2UgZG8gb2NjYXNpb25hbGx5IGVhdCBsdW5jaCB0b2dldGhlci4gTW9yZW92ZXIsIGluIGNhc2VzIG9mIGRpc2FncmVlbWVudCAoWCBzYXlzIGhlIGFza3MgWSBmb3IgYWR2aWNlOyBZIGRvZXNuJ3QgYWdyZWUpLCB0aGUgImdyb3VuZCB0cnV0aCIgZWdvY2VudHJpYyBuZXR3b3JrIHdvdWxkIHRoZW4gaGluZ2Ugb24gdGhlIHJlc2VhcmNoZXIncyBkZWNpc2lvbiB0byB1c2UgYW4gaW50ZXJzZWN0aW9uIHZzIHVuaW9uIHJ1bGUgdG8gcmVzb2x2ZSBkaXNhZ3JlZW1lbnRzOyBLcmFja2hhcmR0IG5vdGVzIHRoaXMgaW4gaGlzIHBhcGVyLiBCeSBhbHRlcm5hdGl2ZWx5IGRlZmluaW5nIHRoZSBlZ29jZW50cmljIG5ldHdvcmsgYmFzZWQgc29sZWx5IG9uIHRoZSByZXNwb25zZXMgdGhhdCBzdWJqZWN0cyB3b3VsZCBoYXZlIGdyZWF0ZXN0IGludHJvc3BlY3RpdmUgYWNjZXNzIHRvICh0aGVpciBvd24gYWR2aWNlLXNlZWtpbmcgYmVoYXZpb3IpLCB3ZSBzaWRlc3RlcCB0aGlzIHJlc2VhcmNoZXIgZGVncmVlIG9mIGZyZWVkb20uCgpgYGB7ciBjbGVhbi1kYXRhfQprcmFja2hhcmR0X3JhdyA8LSBoZXJlKCJkYXRhIiwgImtyYWNraGFyZHQiKSAlPiUKICBmczo6ZGlyX2xzKHJlZ2V4cCA9ICJrcmFja2hhcmR0X3RlY2hfbWFuYWdlcnNfc3ViW1s6ZGlnaXQ6XV17Mn1cXC5jc3YiKSAlPiUKICBtYXBfZGZyKAogICAgLmYgPSB+cmVhZF9jc3YoLngsIGNvbF9uYW1lcyA9IEZBTFNFLCBzaG93X2NvbF90eXBlcyA9IEZBTFNFKSwKICAgIC5pZCA9ICJmaWxlbmFtZSIKICApICU+JQogIG11dGF0ZSgKICAgIHN1Yl9pZCA9IHN0cl9leHRyYWN0KGZpbGVuYW1lLCAic3ViW1s6ZGlnaXQ6XV17Mn0iKSwKICAgIHN1Yl9pZCA9IHN0cl9yZW1vdmUoc3ViX2lkLCAic3ViIiksCiAgICBzdWJfaWQgPSBhcy5udW1lcmljKHN1Yl9pZCkKICApICU+JQogIHNlbGVjdCgtZmlsZW5hbWUpICU+JQogIGdyb3VwX2J5KHN1Yl9pZCkgJT4lCiAgbXV0YXRlKGZyb20gPSByb3dfbnVtYmVyKCkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBwaXZvdF9sb25nZXIoCiAgICBjb2xzID0gLWMoc3ViX2lkLCBmcm9tKSwKICAgIG5hbWVzX3RvID0gInRvIiwKICAgIHZhbHVlc190byA9ICJlZGdlIgogICkgJT4lCiAgbXV0YXRlKAogICAgdG8gPSBzdHJfcmVtb3ZlKHRvLCAiWCIpLAogICAgdG8gPSBhcy5pbnRlZ2VyKHRvKQogICkKCmtyYWNraGFyZHRfZWdvY2VudHJpYyA8LSBrcmFja2hhcmR0X3JhdyAlPiUKICBmaWx0ZXIoc3ViX2lkID09IGZyb20sIGZyb20gIT0gdG8pICU+JQogIHNlbGVjdCgtc3ViX2lkKQoKa3JhY2toYXJkdF9hbGxvY2VudHJpYyA8LSBrcmFja2hhcmR0X3JhdyAlPiUKICBmaWx0ZXIoc3ViX2lkICE9IGZyb20sIGZyb20gIT0gdG8pCmBgYAoKCiMgUGxvdCBkYXRhCgpPa2F5LCBsZXQncyB0cnkgYW5kIGdldCBhIHNlbnNlIGZvciB3aGF0IHRoZSAiZWdvY2VudHJpYyIgbmV0d29yayBsb29rcyBsaWtlLgoKYGBge3IgbmV0d29yay1ncmFwaH0Ka3JhY2toYXJkdF9nIDwtIGtyYWNraGFyZHRfZWdvY2VudHJpYyAlPiUKICBmaWx0ZXIoZWRnZSA9PSAxKSAlPiUKICBzZWxlY3QoLWVkZ2UpICU+JSAKICB0YmxfZ3JhcGgoZWRnZXMgPSAuKSAlPiUKICBtdXRhdGUobmFtZSA9IHJvd19udW1iZXIoKSkKCnBsb3RfbmV0d29ya19ncmFwaCA8LSBrcmFja2hhcmR0X2cgJT4lCiAgbXV0YXRlKERlZ3JlZSA9IGNlbnRyYWxpdHlfZGVncmVlKG1vZGUgPSAiaW4iKSkgJT4lCiAgIyBQbG90IHRoZSAiZ3JvdW5kIHRydXRoIiBuZXR3b3JrCiAgZ2dyYXBoKGxheW91dCA9ICJzdHJlc3MiKSArCiAgZ2VvbV9lZGdlX2xpbmsoCiAgICBhZXMoCiAgICAgIHN0YXJ0X2NhcCA9IGxhYmVsX3JlY3Qobm9kZTEubmFtZSwgcGFkZGluZyA9IG1hcmdpbigxNSwgMTUsIDE1LCAxNSkpLAogICAgICBlbmRfY2FwID0gbGFiZWxfcmVjdChub2RlMi5uYW1lLCBwYWRkaW5nID0gbWFyZ2luKDE1LCAxNSwgMTUsIDE1KSksCiAgICApLAogICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDUsICJwdCIpLCB0eXBlID0gImNsb3NlZCIpCiAgKSArCiAgZ2VvbV9ub2RlX2xhYmVsKAogICAgYWVzKGxhYmVsID0gbmFtZSwgc2l6ZSA9IERlZ3JlZSksCiAgICBmaWxsID0gImdyZXk5NSIsIHNob3cubGVnZW5kID0gRkFMU0UKICApICsKICBzY2FsZV9zaXplKHJhbmdlID0gYygzLCAxMCkpICsKICB0aGVtZSgKICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTMpLAogICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDEzKSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iCiAgKQoKcGxvdF9uZXR3b3JrX2dyYXBoCmBgYAoKV2UgY2FuIGFsc28gcGxvdCB0aGlzIGFzIGEgbWF0cml4IGluc3RlYWQgb2YgYSBncmFwaCwgd2hpY2ggd2lsbCBlYXNlIGNvbXBhcmlzb24gd2l0aCB0aGUgY29nbml0aXZlIHN0cmF0ZWdpZXMgd2UnbGwgY29uc2lkZXIgbmV4dC4KCmBgYHtyIG5ldHdvcmstYWRqYWNlbmN5fQpwbG90X25ldHdvcmtfYWRqIDwtIGtyYWNraGFyZHRfZWdvY2VudHJpYyAlPiUKICBwbG90X3JlcHJlc2VudGF0aW9uKGVkZ2UsIG5fYnJlYWtzID0gMikgKwogIGdndGl0bGUoIkVnb2NlbnRyaWMgTmV0d29yayIpCgpwbG90X25ldHdvcmtfYWRqCmBgYAoKSG93IGRvZXMgdGhpcyBjb21wYXJlIHRvIHN1YmplY3RzJyBtZW50YWwgcmVwcmVzZW50YXRpb24gb2YgdGhlIG5ldHdvcms/CgpgYGB7ciBwbG90LXJlcHJlc2VudGF0aW9ufQpwbG90X2Nob2ljZSA8LSBrcmFja2hhcmR0X2FsbG9jZW50cmljICU+JQogIHBsb3RfcmVwcmVzZW50YXRpb24ocmVsYXRpb25fdmFsdWUgPSBlZGdlKSArCiAgZ2d0aXRsZSgiTmV0d29yayBSZXByZXNlbnRhdGlvbiIpCgpwbG90X25ldHdvcmtfYWRqIHwgcGxvdF9jaG9pY2UKYGBgCgpJbiB0aGUgb3JpZ2luYWwgcGFwZXIsIEtyYWNraGFyZHQgbWFrZXMgdGhlIGZvbGxvd2luZyBub3RlOiAiVGhlcmUgYXJlIHNvbWUgY2VudGVycyBvZiBmb2N1cyBmb3IgYWR2aWNlLCBub3RhYmx5IDIgYW5kIDIxIChib3RoIGFyZSB2aWNlIHByZXNpZGVudHMpIC4uLiBJbiBbdGhlIHN1YmplY3RpdmVseSBwZXJjZWl2ZWQgbmV0d29ya10sIDIxIGxvc2VzIGhpcyBwcm9taW5lbmNlIGFzIGEgbWFqb3IgcmVjaXBpZW50IG9mIG5vbWluYXRpb25zOiBpbnN0ZWFkLCAxOCwgMTQsIGFuZCA3ICh0aGUgcHJlc2lkZW50KSBhcHBlYXIgdG8gYmUgbW9yZSBjZW50cmFsLiIgVG8gZ2V0IGEgcXVhbnRpdGF0aXZlIHNlbnNlIGZvciB0aGlzIGluIG91ciBkYXRhLCB3ZSBjYW4gdHJ5IGNhbGN1bGF0aW5nIHRoZSAicGVyY2VpdmVkIiBkZWdyZWUgY2VudHJhbGl0eSBieSBzdW1taW5nIG92ZXIgdGhlIG1hdHJpeCBjb2x1bW5zLCB0aGVuIGNvbXBhcmluZyB0aGF0IGFnYWluc3QgdGhlICJ0cnVlIiBpbi1kZWdyZWUgY2VudHJhbGl0eS4KCmBgYHtyIGNhbGMtY2VudHJhbGl0eS1kaWZmfQpjZW50cmFsaXR5X2RpZmZlcmVuY2VzIDwtIGtyYWNraGFyZHRfZyAlPiUKICBtdXRhdGUoCiAgICBEZWdyZWUgPSBjZW50cmFsaXR5X2RlZ3JlZShtb2RlID0gImluIiksCiAgICBCZXR3ZWVubmVzcyA9IGNlbnRyYWxpdHlfYmV0d2Vlbm5lc3MoZGlyZWN0ZWQgPSBUUlVFKQogICkgJT4lCiAgYXNfdGliYmxlKCkgJT4lCiAgIyBBZGQgcmVwcmVzZW50ZWQgaW4tZGVncmVlOyBzdGFuZGFyZGl6ZSBzdW0gYnkgbnVtYmVyIG9mIG5ldHdvcmsgbWVtYmVycwogIGxlZnRfam9pbigKICAgIGtyYWNraGFyZHRfYWxsb2NlbnRyaWMgJT4lCiAgICAgIGdyb3VwX2J5KG5hbWUgPSB0bykgJT4lCiAgICAgIHN1bW1hcmlzZShQZXJjZWl2ZWQgPSBzdW0oZWRnZSkvMjEsIC5ncm91cHMgPSAiZHJvcCIpLAogICAgYnkgPSBjKCJuYW1lIikKICApICU+JQogIHNlbGVjdChuYW1lLCBQZXJjZWl2ZWQsIGV2ZXJ5dGhpbmcoKSkgJT4lCiAgYXJyYW5nZShkZXNjKERlZ3JlZSksIGRlc2MoUGVyY2VpdmVkKSkKYGBgCgpXZSBjYW4gc2VlIHRoYXQgdGhlIHNhbWUgbnVtYmVyIG9mIG1hbmFnZXJzIGdvIHRvIHN1YmplY3RzIDE4IGFuZCAyMSBmb3IgYWR2aWNlICgxNSBlYWNoKSwgYnV0IHRoYXQgc3ViamVjdCAxOCBpcyBwZXJjZWl2ZWQgYXMgYmVpbmcgbXVjaCBtb3JlICJwb3B1bGFyIiAoYXZlcmFnZWQgYWNyb3NzIHN1YmplY3RzLCAxMS45NSBtYW5hZ2VycyBhcmUgcGVyY2VpdmVkIHRvIGdvIHRvIGhpbSBmb3IgYWR2aWNlKSB0aGFuIHN1YmplY3QgMjEgKGF2ZXJhZ2VkIGFjcm9zcyBzdWJqZWN0cywgOC4zOCBtYW5hZ2VycyBhcmUgcGVyY2VpdmVkIHRvIGdvIHRvIGhpbSBmb3IgYWR2aWNlKS4gQSBzaW1pbGFyIHBoZW5vbWVub24gaGFwcGVucyB3aXRoIHN1YmplY3RzIDEgYW5kIDcsIHdoZXJlIHN1YmplY3QgMSBpcyBwZXJjZWl2ZWQgYXMgYmVpbmcgbXVjaCBsZXNzIHBvcHVsYXIgdGhhbiBzdWJqZWN0IDcsIGRlc3BpdGUgdGhlaXIgaGF2aW5nIHRoZSBzYW1lICJ0cnVlIiBwb3B1bGFyaXR5LgoKYGBge3IgY2VudHJhbGl0eS1kaWZmLWRlZ3JlZX0KY2VudHJhbGl0eV9kaWZmZXJlbmNlcyAlPiUKICBnZ3Bsb3QoYWVzKHg9RGVncmVlLCB5PVBlcmNlaXZlZCkpICsKICBnZyArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSkgKwogIGdlb21fbGFiZWwoYWVzKGxhYmVsID0gbmFtZSkpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobmFtZSA9ICJUcnVlIChkZWdyZWUpIGNlbnRyYWxpdHkiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKG5hbWUgPSAiUGVyY2VpdmVkIGNlbnRyYWxpdHkiKQoKY2VudHJhbGl0eV9kaWZmZXJlbmNlcyAlPiUKICBzZWxlY3QobmFtZSwgRGVncmVlLCBQZXJjZWl2ZWQpICU+JQogIGthYmxlKCkKYGBgCgpJcyBpdCBwb3NzaWJsZSB0aGF0IHN1YmplY3RzJyBuZXR3b3JrIHJlcHJlc2VudGF0aW9ucyBtaWdodCBiZSByZWZsZWN0aW5nIHNvbWUgb3RoZXIgY2VudHJhbGl0eSBtZXRyaWM/IEluIHRoZSBvcmlnaW5hbCBwYXBlciwgS3JhY2toYXJkdCBub3RlcyB0aGF0IGJldHdlZW5uZXNzIHNlZW1zIHRvIGhhdmUgc29tZSBwcmVkaWN0aXZlIHBvd2VyLiBGb3IgdGhlIDE4LTIxIGFuZCAxLTcgdGVzdCBjYXNlcywgd2Ugc2VlIHRoYXQgYmV0d2Vlbm5lc3MgY2VudHJhbGl0eSBkb2VzIG1ha2UgdGhlICJjb3JyZWN0IiBwcmVkaWN0aW9uIGFib3V0IHdoaWNoIG5ldHdvcmsgbWVtYmVyIGlzIHJlcHJlc2VudGVkIGFzIGJlaW5nIG1vcmUgaW1wb3J0YW50LiBCdXQsIHdlIHNob3VsZCBub3RlIHRoYXQgYmV0d2Vlbm5lc3MgZG9lc24ndCBkbyB0aGUgZ3JlYXRlc3Qgam9iIHByZWRpY3RpbmcgcGVyY2VpdmVkIHBvcHVsYXJpdHkgYWNyb3NzIHRoZSBib2FyZDsgaXRzIGdyZWF0ZXN0IHByZWRpY3RpdmUgcG93ZXIgaXMgaW4gZXhwbGFpbmluZyB0aGUgcG9wdWxhcml0eSBkaXNjcmVwYW5jeSBmb3IgdGhlIG1vc3QgcG9wdWxhciBtYW5hZ2Vycy4KCmBgYHtyIGNlbnRyYWxpdHktZGlmZmVyZW5jZXMtYmV0d2Vlbn0KY2VudHJhbGl0eV9kaWZmZXJlbmNlcyAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IERlZ3JlZTpCZXR3ZWVubmVzcywgbmFtZXNfdG8gPSAibWV0cmljIikgJT4lCiAgZ2dwbG90KGFlcyh4PXZhbHVlLCB5PVBlcmNlaXZlZCkpICsKICBnZyArCiAgZmFjZXRfd3JhcCh+bWV0cmljLCBzY2FsZXMgPSAiZnJlZV94IikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UpICsKICBnZW9tX2xhYmVsKGFlcyhsYWJlbCA9IG5hbWUpKSArCiAgc2NhbGVfeF9jb250aW51b3VzKG5hbWUgPSAiVHJ1ZSBjZW50cmFsaXR5IikgKwogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIlBlcmNlaXZlZCBjZW50cmFsaXR5IikKCmNlbnRyYWxpdHlfZGlmZmVyZW5jZXMgJT4lCiAga2FibGUoKQpgYGAKCgojIFNpbXVsYXRlZCBvYnNlcnZhdGlvbnMKCldlIGtub3cgdGhhdCBhbiBpbmRpdmlkdWFsJ3MgZW1iZWRkaW5nIHdpdGhpbiBhIG5ldHdvcmsgZGljdGF0ZXMgd2hhdCBpbnRlcmFjdGlvbnMgYW5kL29yIHJlbGF0aW9uc2hpcHMgdGhleSdyZSBhYmxlIHRvIG9ic2VydmUuIFRoZXJlZm9yZSwgd2hlbiBidWlsZGluZyBwcmVkaWN0ZWQgY29nbml0aXZlIG1hcHMsIHdlIHNob3VsZCB1c2UgYSBkaWZmZXJlbnQgc2V0IG9mIGludGVyYWN0aW9ucyB0byBpbmZvcm0gZWFjaCBzdWJqZWN0J3MgcHJlZGljdGVkIHJlcHJlc2VudGF0aW9ucy4gT2YgY291cnNlLCB3ZSBoYXZlIG5vIGlkZWEgd2hhdCBpbmRpdmlkdWFsIHN1YmplY3RzJyBvYnNlcnZhdGlvbnMgYWN0dWFsbHkgYXJlLiBTbyB3ZSdsbCBuZWVkIHRvIGNvbWUgdXAgd2l0aCBhIGNvbXBhY3QgYW5kIHJlYXNvbmFibGUgc2V0IG9mIGFzc3VtcHRpb25zIGFib3V0IHdoYXQgb2JzZXJ2YXRpb25zIHdlcmUgbW9zdCBsaWtlbHkgYXZhaWxhYmxlIHRvIGluZGl2aWR1YWwgbmV0d29yayBtZW1iZXJzLgoKSGVyZSBhcmUgdGhyZWUga2V5IGFzc3VtcHRpb25zIHdlJ2xsIG1ha2UgaGVyZToKCjEuIFdlJ2xsIGFzc3VtZSAodHJpdmlhbGx5KSB0aGF0IHBlb3BsZSBjYW4gb2JzZXJ2ZSBpbnRlcmFjdGlvbnMgYmV0d2VlbiB0aGVtc2VsdmVzIGFuZCB0aGVpciBpbW1lZGlhdGUgYWR2aXNvcnMgKGFuZC9vciBhZHZpc2VlcykuCjIuIFdlJ2xsIGFsc28gYXNzdW1lIHRoYXQgcGVvcGxlIGFyZSBnZW5lcmFsbHkgYWJsZSB0byBvYnNlcnZlIGludGVyYWN0aW9ucyBiZXR3ZWVuIGFkdmlzb3JzLW9mLWFkdmlzb3JzIChhbmQvb3IgYWR2aXNlZXMtb2YtYWR2aXNlZXMpLCBlaXRoZXIgdGhyb3VnaCBmaXJzdGhhbmQgb2JzZXJ2YXRpb24gb3Igc2Vjb25kaGFuZCBjaGF0dGVyLgozLiBUaG91Z2ggb2YgY291cnNlIGl0J3MgcGxhdXNpYmxlIHRoYXQgcGVvcGxlIG1pZ2h0IG9ic2VydmUgbW9yZSBkaXN0YW50IGludGVyYWN0aW9ucywgd2UnbGwgYXNzdW1lIHRoaXMgaGFwcGVucyB3aXRoIGVub3VnaCBpbmZyZXF1ZW5jeSB0aGF0IHdlIGNhbiBpZ25vcmUgdGhvc2UgaW50ZXJhY3Rpb25zIGZvciB0aGUgc2FrZSBvZiBtb2RlbGluZy4KCldlJ3ZlIGxlZnQgb3BlbiBhbiBhbWJpZ3VpdHkgaW4gdGhvc2UgYXNzdW1wdGlvbnM6IGFyZSBwZW9wbGUgb2JzZXJ2aW5nIGFkdmlzb3JzLW9mLWFkdmlzb3JzLCBhbmQvb3IgYWR2aXNlZXMtb2YtYWR2aXNlZXM/IFRvIGFpZCB1bmRlcnN0YW5kaW5nLCB3ZSdsbCB1c2UgdGhlIGZvbGxvd2luZyBleGFtcGxlLiBTdXBwb3NlIHdlJ3JlIGxvb2tpbmcgYXQgYSBzdWJzZXQgb2YgYSBuZXR3b3JrIGNvbnNpc3Rpbmcgb2YgdGhlIGdyYWQgc3R1ZGVudCBBYmJ5LCB3aG8gYXNrcyB0aGUgcG9zdGRvYyBCZXR0eSBmb3IgYWR2aWNlOyBpbiB0dXJuLCBCZXR0eSB0aGUgcG9zdGRvYyBhc2tzIENhdGh5IHRoZSBhc3Npc3RhbnQgcHJvZmVzc29yIGZvciBhZHZpY2U7IGFuZCBDYXRoeSBhc2tzIERhbmkgdGhlIGFzc29jaWF0ZSBwcm9mZXNzb3IgZm9yIGFkdmljZS4gVGhlcmUgYXJlIHRocmVlIHJlYXNvbmFibGUgd2F5cyB0aGF0IG9ic2VydmF0aW9ucyBtaWdodCB3b3JrIGluIHRoaXMgbmV0d29yazoKCjEuIE9ic2VydmF0aW9ucyBnbyAib3V0IjogV2hlbiBBYmJ5IGFza3MgQmV0dHkgZm9yIGFkdmljZSwgQmV0dHkgcmVzcG9uZHMgYnkgc2hhcmluZyB0aGUgd2lzZG9tIHNoZSdzIGdhaW5lZCBmcm9tIGFza2luZyBDYXRoeSBmb3IgYWR2aWNlLiBUaGF0IGxlYWRzIEFiYnkgdG8gb2JzZXJ2ZSB0aGF0IEJldHR5IGdvZXMgdG8gQ2F0aHkgZm9yIGFkdmljZS4KMi4gT2JzZXJ2YXRpb25zIGdvICJpbiI6IEJldHR5IGhhcyBhc2tlZCBDYXRoeSBmb3IgYWR2aWNlLiBDYXRoeSB0aGlua3MgQmV0dHkgaGFzIGFza2VkIGEgZ3JlYXQgcXVlc3Rpb24gdGhhdCBzaGUgZG9lc24ndCBrbm93IHRoZSBhbnN3ZXIgdG8sIHNvIENhdGh5IGFza3MgRGFuaSBhYm91dCBpdC4gVGhhdCBsZWFkcyBEYW5pIHRvIG9ic2VydmUgdGhhdCBCZXR0eSBnb2VzIHRvIENhdGh5IGZvciBhZHZpY2UuCjMuIEl0IGdvZXMgYm90aCB3YXlzLgoKV2UgbWF5IGJlIGFibGUgdG8gdGVzdCB0aGlzIGVtcGlyaWNhbGx5LiBXZSB3b3VsZCBuZWVkIHRvIHNpbXVsYXRlIGEgc2V0IG9mIG9ic2VydmF0aW9ucyBjb25zaXN0ZW50IHdpdGggYWxsIHRocmVlIHBvc3NpYmlsaXRpZXMsIGdlbmVyYXRlIG1vZGVsIHByZWRpY3Rpb25zIGZyb20gdGhvc2Ugc2ltdWxhdGlvbnMsIHRoZW4gY29tcGFyZSBob3cgd2VsbCB0aG9zZSBtb2RlbHMgZml0IG1hbmFnZXJzJyBhY3R1YWwgcGVyY2VwdGlvbnMgb2YgdGhlIG5ldHdvcmsuCgpgYGB7ciBkZWYtb2JzZXJ2YXRpb25zfQojIE9ic2VydmF0aW9ucyBnbyBib3RoIHdheXMKb2JzX2VkZ2VsaXN0X2FsbCA8LSBleHBhbmRfZ3JpZCgKICBzdWJfaWQgPSAxOjIxLAogICMgU3RhcnQgd2l0aCBhbGwgb25lLXN0ZXAgZWdvY2VudHJpYyBvYnNlcnZhdGlvbnMKICBrcmFja2hhcmR0X2Vnb2NlbnRyaWMKKSAlPiUKICAjIENvbnZlcnQgYWRqbGlzdCBpbnRvIGVkZ2VsaXN0CiAgZmlsdGVyKGVkZ2UgPT0gMSkgJT4lCiAgc2VsZWN0KC1lZGdlKSAlPiUKICAjIEZvciBhIGdpdmVuIG5vZGUsIHdlIHdhbnQgdG8ga25vdyB3aG8gdGhlaXIgImFkdmlzb3JzLW9mLWFkdmlzb3JzIiBhcmUKICAjIChvciBlcXVpdmFsZW50bHksICJhZHZpc2Vlcy1vZi1hZHZpc2VlcyIpCiAgbGVmdF9qb2luKAogICAga3JhY2toYXJkdF9nICU+JQogICAgICBtdXRhdGUobmVpZ2hib3JzID0gbG9jYWxfbWVtYmVycyhvcmRlciA9IDEsIG1vZGUgPSAiYWxsIikpICU+JQogICAgICBhc190aWJibGUoKSwKICAgIGJ5ID0gYygic3ViX2lkIiA9ICJuYW1lIikKICApICU+JQogICMgV2UgYXNzdW1lIHRoYXQgbm9kZXMgYXJlIGFibGUgdG8gb2JzZXJ2ZSAoZGlyZWN0bHkgb3IgdGhyb3VnaCBjaGF0dGVyKQogICMgYWR2aWNlLWdpdmluZyBpbnRlcmFjdGlvbnMgZnJvbSB0aGVpciBhZHZpc29ycyBhbmQgYWR2aXNvcnMtb2YtYWR2aXNvcnMKICAjIChvciBlcXVpdmFsZW50bHksIGFkdmlzZWVzIGFuZCBhZHZpc2Vlcy1vZi1hZHZpc2VlcykKICByb3d3aXNlKCkgJT4lCiAgZmlsdGVyKChmcm9tICVpbiUgbmVpZ2hib3JzKSB8ICh0byAlaW4lIG5laWdoYm9ycykpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBzZWxlY3QoLW5laWdoYm9ycykgJT4lCiAgIyBNYWtlIHByZXR0eQogIGFycmFuZ2Uoc3ViX2lkLCBmcm9tKQoKIyBBZHZpc2VlcyBvYnNlcnZlIHdobyBhZHZpc2VzIHRoZWlyIGFkdmlzb3JzCm9ic19lZGdlbGlzdF9vdXQgPC0gZXhwYW5kX2dyaWQoCiAgc3ViX2lkID0gMToyMSwKICBrcmFja2hhcmR0X2Vnb2NlbnRyaWMKKSAlPiUKICBmaWx0ZXIoZWRnZSA9PSAxKSAlPiUKICBzZWxlY3QoLWVkZ2UpICU+JQogIGxlZnRfam9pbigKICAgIGtyYWNraGFyZHRfZyAlPiUKICAgICAgbXV0YXRlKG5laWdoYm9ycyA9IGxvY2FsX21lbWJlcnMob3JkZXIgPSAxLCBtb2RlID0gIm91dCIpKSAlPiUKICAgICAgYXNfdGliYmxlKCksCiAgICBieSA9IGMoInN1Yl9pZCIgPSAibmFtZSIpCiAgKSAlPiUKICByb3d3aXNlKCkgJT4lCiAgZmlsdGVyKChmcm9tICVpbiUgbmVpZ2hib3JzKSB8ICh0byAlaW4lIG5laWdoYm9ycykpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBzZWxlY3QoLW5laWdoYm9ycykgJT4lCiAgYXJyYW5nZShzdWJfaWQsIGZyb20pCgojIEFkdmlzb3JzIG9ic2VydmUgd2hvIHRoZWlyIGFkdmlzZWVzIGFkdmlzZQpvYnNfZWRnZWxpc3RfaW4gPC0gZXhwYW5kX2dyaWQoCiAgc3ViX2lkID0gMToyMSwKICBrcmFja2hhcmR0X2Vnb2NlbnRyaWMKKSAlPiUKICBmaWx0ZXIoZWRnZSA9PSAxKSAlPiUKICBzZWxlY3QoLWVkZ2UpICU+JQogIGxlZnRfam9pbigKICAgIGtyYWNraGFyZHRfZyAlPiUKICAgICAgbXV0YXRlKG5laWdoYm9ycyA9IGxvY2FsX21lbWJlcnMob3JkZXIgPSAxLCBtb2RlID0gImluIikpICU+JQogICAgICBhc190aWJibGUoKSwKICAgIGJ5ID0gYygic3ViX2lkIiA9ICJuYW1lIikKICApICU+JQogIHJvd3dpc2UoKSAlPiUKICBmaWx0ZXIoKGZyb20gJWluJSBuZWlnaGJvcnMpIHwgKHRvICVpbiUgbmVpZ2hib3JzKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIHNlbGVjdCgtbmVpZ2hib3JzKSAlPiUKICBhcnJhbmdlKHN1Yl9pZCwgZnJvbSkKCm9ic19hZGpsaXN0X2FsbCA8LSBleHBhbmRfZ3JpZChzdWJfaWQgPSAxOjIxLCBmcm9tID0gc3ViX2lkLCB0byA9IHN1Yl9pZCkgJT4lCiAgbGVmdF9qb2luKAogICAgb2JzX2VkZ2VsaXN0X2FsbCAlPiUgbXV0YXRlKGVkZ2UgPSAxKSwKICAgIGJ5ID0gYygic3ViX2lkIiwgImZyb20iLCAidG8iKQogICkgJT4lCiAgbXV0YXRlKGVkZ2UgPSBpZl9lbHNlKGlzLm5hKGVkZ2UpLCAwLCBlZGdlKSkKCm9ic19hZGpsaXN0X291dCA8LSBleHBhbmRfZ3JpZChzdWJfaWQgPSAxOjIxLCBmcm9tID0gc3ViX2lkLCB0byA9IHN1Yl9pZCkgJT4lCiAgbGVmdF9qb2luKAogICAgb2JzX2VkZ2VsaXN0X291dCAlPiUgbXV0YXRlKGVkZ2UgPSAxKSwKICAgIGJ5ID0gYygic3ViX2lkIiwgImZyb20iLCAidG8iKQogICkgJT4lCiAgbXV0YXRlKGVkZ2UgPSBpZl9lbHNlKGlzLm5hKGVkZ2UpLCAwLCBlZGdlKSkKCm9ic19hZGpsaXN0X2luIDwtIGV4cGFuZF9ncmlkKHN1Yl9pZCA9IDE6MjEsIGZyb20gPSBzdWJfaWQsIHRvID0gc3ViX2lkKSAlPiUKICBsZWZ0X2pvaW4oCiAgICBvYnNfZWRnZWxpc3RfaW4gJT4lIG11dGF0ZShlZGdlID0gMSksCiAgICBieSA9IGMoInN1Yl9pZCIsICJmcm9tIiwgInRvIikKICApICU+JQogIG11dGF0ZShlZGdlID0gaWZfZWxzZShpcy5uYShlZGdlKSwgMCwgZWRnZSkpCmBgYAoKCiMgU2NoZW1hLWJhc2VkIHJlcHJlc2VudGF0aW9uCgpJZiBwZW9wbGUgd2VyZSB1c2luZyB0cmlhZCBvciBjb21tdW5pdHkgc2NoZW1hcy9oZXVyaXN0aWNzIHRvIGluZm9ybSByZXByZXNlbnRhdGlvbiwgd2hhdCB3b3VsZCB0aGlzIGxvb2sgbGlrZT8gVXNpbmcgbGl0ZXJhbGx5IHRoZSBleGFjdCBzYW1lIHRvb2xzIHRoYXQgd2UgdXNlZCB0byBhbmFseXplIHRoZSBidXR0ZXJmbHkgbmV0d29yaywgbGV0J3MgY3JlYXRlIHNvbWUgcHJlZGljdGVkIHJlcHJlc2VudGF0aW9ucy4KCmBgYHtyIHNjaGVtYS1leHBlcnRzfQpzY2hlbWFfZXhwZXJ0c19hbGwgPC0gb2JzX2Fkamxpc3RfYWxsICU+JQogICMgTWVtb3JpemF0aW9uCiAgZ3JvdXBfYnkoc3ViX2lkLCBmcm9tKSAlPiUKICBtdXRhdGUoCiAgICBtZW1fdmFsdWUgPSBlZGdlIC8gc3VtKGVkZ2UpLAogICAgbWVtX3ZhbHVlID0gaWZfZWxzZShpcy5uYW4obWVtX3ZhbHVlKSwgMCwgbWVtX3ZhbHVlKQogICkgJT4lCiAgdW5ncm91cCgpICU+JQogICMgTm93IHRyaWFkcwogIGxlZnRfam9pbigKICAgIG9ic19hZGpsaXN0X2FsbCAlPiUKICAgICAgZ3JvdXBfYnkoc3ViX2lkKSAlPiUKICAgICAgbmVzdCgpICU+JQogICAgICBtdXRhdGUodHJpYWQgPSBtYXAoZGF0YSwgfmJ1aWxkX3JlcF90cmlhZCgueCwgImVkZ2UiKSkpICU+JQogICAgICB1bm5lc3QodHJpYWQpICU+JQogICAgICB1bmdyb3VwKCkgJT4lCiAgICAgIHNlbGVjdCgtYyhkYXRhLCB0cmFuc2l0aW9uX3NjYWxpbmcpKSAlPiUKICAgICAgbXV0YXRlKHRyaWFkX3ZhbHVlID0gaWZfZWxzZShpcy5uYW4odHJpYWRfdmFsdWUpLCAwLCB0cmlhZF92YWx1ZSkpLAogICAgYnkgPSBjKCJzdWJfaWQiLCAiZnJvbSIsICJ0byIpCiAgKSAlPiUKICAjIEZpbmFsbHkgY29tbXVuaXRpZXMKICBsZWZ0X2pvaW4oCiAgICBvYnNfYWRqbGlzdF9hbGwgJT4lCiAgICAgIGdyb3VwX2J5KHN1Yl9pZCkgJT4lCiAgICAgIG5lc3QoKSAlPiUKICAgICAgbXV0YXRlKGNvbW0gPSBtYXAoZGF0YSwgfmJ1aWxkX3JlcF9jb21tdW5pdHkoLngsICJlZGdlIikpKSAlPiUKICAgICAgdW5uZXN0KGNvbW0pICU+JQogICAgICB1bmdyb3VwKCkgJT4lCiAgICAgIHNlbGVjdCgtYyhkYXRhLCB0cmFuc2l0aW9uX3NjYWxpbmcpKSwKICAgIGJ5ID0gYygic3ViX2lkIiwgImZyb20iLCAidG8iKQogICkKCnNjaGVtYV9leHBlcnRzX291dCA8LSBvYnNfYWRqbGlzdF9vdXQgJT4lCiAgIyBNZW1vcml6YXRpb24KICBncm91cF9ieShzdWJfaWQsIGZyb20pICU+JQogIG11dGF0ZSgKICAgIG1lbV92YWx1ZSA9IGVkZ2UgLyBzdW0oZWRnZSksCiAgICBtZW1fdmFsdWUgPSBpZl9lbHNlKGlzLm5hbihtZW1fdmFsdWUpLCAwLCBtZW1fdmFsdWUpCiAgKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgIyBOb3cgdHJpYWRzCiAgbGVmdF9qb2luKAogICAgb2JzX2Fkamxpc3Rfb3V0ICU+JQogICAgICBncm91cF9ieShzdWJfaWQpICU+JQogICAgICBuZXN0KCkgJT4lCiAgICAgIG11dGF0ZSh0cmlhZCA9IG1hcChkYXRhLCB+YnVpbGRfcmVwX3RyaWFkKC54LCAiZWRnZSIpKSkgJT4lCiAgICAgIHVubmVzdCh0cmlhZCkgJT4lCiAgICAgIHVuZ3JvdXAoKSAlPiUKICAgICAgc2VsZWN0KC1jKGRhdGEsIHRyYW5zaXRpb25fc2NhbGluZykpICU+JQogICAgICBtdXRhdGUodHJpYWRfdmFsdWUgPSBpZl9lbHNlKGlzLm5hbih0cmlhZF92YWx1ZSksIDAsIHRyaWFkX3ZhbHVlKSksCiAgICBieSA9IGMoInN1Yl9pZCIsICJmcm9tIiwgInRvIikKICApICU+JQogICMgRmluYWxseSBjb21tdW5pdGllcwogIGxlZnRfam9pbigKICAgIG9ic19hZGpsaXN0X291dCAlPiUKICAgICAgZ3JvdXBfYnkoc3ViX2lkKSAlPiUKICAgICAgbmVzdCgpICU+JQogICAgICBtdXRhdGUoY29tbSA9IG1hcChkYXRhLCB+YnVpbGRfcmVwX2NvbW11bml0eSgueCwgImVkZ2UiKSkpICU+JQogICAgICB1bm5lc3QoY29tbSkgJT4lCiAgICAgIHVuZ3JvdXAoKSAlPiUKICAgICAgc2VsZWN0KC1jKGRhdGEsIHRyYW5zaXRpb25fc2NhbGluZykpLAogICAgYnkgPSBjKCJzdWJfaWQiLCAiZnJvbSIsICJ0byIpCiAgKQoKc2NoZW1hX2V4cGVydHNfaW4gPC0gb2JzX2Fkamxpc3RfaW4gJT4lCiAgIyBNZW1vcml6YXRpb24KICBncm91cF9ieShzdWJfaWQsIGZyb20pICU+JQogIG11dGF0ZSgKICAgIG1lbV92YWx1ZSA9IGVkZ2UgLyBzdW0oZWRnZSksCiAgICBtZW1fdmFsdWUgPSBpZl9lbHNlKGlzLm5hbihtZW1fdmFsdWUpLCAwLCBtZW1fdmFsdWUpCiAgKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgIyBOb3cgdHJpYWRzCiAgbGVmdF9qb2luKAogICAgb2JzX2Fkamxpc3RfaW4gJT4lCiAgICAgIGdyb3VwX2J5KHN1Yl9pZCkgJT4lCiAgICAgIG5lc3QoKSAlPiUKICAgICAgbXV0YXRlKHRyaWFkID0gbWFwKGRhdGEsIH5idWlsZF9yZXBfdHJpYWQoLngsICJlZGdlIikpKSAlPiUKICAgICAgdW5uZXN0KHRyaWFkKSAlPiUKICAgICAgdW5ncm91cCgpICU+JQogICAgICBzZWxlY3QoLWMoZGF0YSwgdHJhbnNpdGlvbl9zY2FsaW5nKSkgJT4lCiAgICAgIG11dGF0ZSh0cmlhZF92YWx1ZSA9IGlmX2Vsc2UoaXMubmFuKHRyaWFkX3ZhbHVlKSwgMCwgdHJpYWRfdmFsdWUpKSwKICAgIGJ5ID0gYygic3ViX2lkIiwgImZyb20iLCAidG8iKQogICkgJT4lCiAgIyBGaW5hbGx5IGNvbW11bml0aWVzCiAgbGVmdF9qb2luKAogICAgb2JzX2Fkamxpc3RfaW4gJT4lCiAgICAgIGdyb3VwX2J5KHN1Yl9pZCkgJT4lCiAgICAgIG5lc3QoKSAlPiUKICAgICAgbXV0YXRlKGNvbW0gPSBtYXAoZGF0YSwgfmJ1aWxkX3JlcF9jb21tdW5pdHkoLngsICJlZGdlIikpKSAlPiUKICAgICAgdW5uZXN0KGNvbW0pICU+JQogICAgICB1bmdyb3VwKCkgJT4lCiAgICAgIHNlbGVjdCgtYyhkYXRhLCB0cmFuc2l0aW9uX3NjYWxpbmcpKSwKICAgIGJ5ID0gYygic3ViX2lkIiwgImZyb20iLCAidG8iKQogICkKYGBgCgpgYGB7ciBwbG90LXNjaGVtYS1hbGx9CnBsb3RfbWVtX2FsbCA8LSBwbG90X3JlcHJlc2VudGF0aW9uKHNjaGVtYV9leHBlcnRzX2FsbCwgbWVtX3ZhbHVlKSArCiAgZ2d0aXRsZSgiTWVtb3JpemF0aW9uIikKCnBsb3RfdHJpYWRfYWxsIDwtIHBsb3RfcmVwcmVzZW50YXRpb24oc2NoZW1hX2V4cGVydHNfYWxsLCB0cmlhZF92YWx1ZSkgKwogIGdndGl0bGUoIlRyaWFkIENvbXBsZXRpb24iKQoKcGxvdF9jb21tX2FsbCA8LSBwbG90X3JlcHJlc2VudGF0aW9uKHNjaGVtYV9leHBlcnRzX2FsbCwgY29tbV92YWx1ZSkgKwogIGdndGl0bGUoIkNvbW11bml0eSBEZXRlY3Rpb24iKQoKcGxvdF9zY2hlbWFzX2FsbCA8LSAoCiAgcGxvdF9jaG9pY2UgfCBwbG90X21lbV9hbGwgfCBwbG90X3RyaWFkX2FsbCB8IHBsb3RfY29tbV9hbGwKKSArCiAgcGxvdF9hbm5vdGF0aW9uKAogICAgdGl0bGUgPSAiT2JzZXJ2YXRpb25zIG9mIGFkdmljZS1naXZpbmcgZ28gYm90aCB3YXlzIiwKICAgIHRoZW1lID0gdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUsIGhqdXN0ID0gMC41KSkKICApCgpwbG90X3NjaGVtYXNfYWxsCgppZiAoa25pdHRpbmcpIHsKICBnZ3NhdmUoCiAgICBoZXJlKCJvdXRwdXRzIiwgIjA3LWtyYWNraGFyZHQiLCAic2NoZW1hX2dhbGxlcnlfYWxsLnBkZiIpLAogICAgcGxvdF9zY2hlbWFzX2FsbCwKICAgIHdpZHRoID0gMTIsIGhlaWdodCA9IDQsCiAgICBkZXZpY2UgPSBjYWlyb19wZGYsIHVuaXRzID0gImluIiwgZHBpID0gMzAwCiAgKQp9CmBgYAoKYGBge3IgcGxvdC1zY2hlbWEtb3V0fQpwbG90X21lbV9vdXQgPC0gcGxvdF9yZXByZXNlbnRhdGlvbihzY2hlbWFfZXhwZXJ0c19vdXQsIG1lbV92YWx1ZSkgKwogIGdndGl0bGUoIk1lbW9yaXphdGlvbiIpCgpwbG90X3RyaWFkX291dCA8LSBwbG90X3JlcHJlc2VudGF0aW9uKHNjaGVtYV9leHBlcnRzX291dCwgdHJpYWRfdmFsdWUpICsKICBnZ3RpdGxlKCJUcmlhZCBDb21wbGV0aW9uIikKCnBsb3RfY29tbV9vdXQgPC0gcGxvdF9yZXByZXNlbnRhdGlvbihzY2hlbWFfZXhwZXJ0c19vdXQsIGNvbW1fdmFsdWUpICsKICBnZ3RpdGxlKCJDb21tdW5pdHkgRGV0ZWN0aW9uIikKCnBsb3Rfc2NoZW1hc19vdXQgPC0gKAogIHBsb3RfY2hvaWNlIHwgcGxvdF9tZW1fb3V0IHwgcGxvdF90cmlhZF9vdXQgfCBwbG90X2NvbW1fb3V0CikgKwogIHBsb3RfYW5ub3RhdGlvbigKICAgIHRpdGxlID0gIkFkdmlzZWVzIG9ic2VydmUgYWR2aXNvcnMnIGFkdmlzb3JzIiwKICAgIHRoZW1lID0gdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUsIGhqdXN0ID0gMC41KSkKICApCgpwbG90X3NjaGVtYXNfb3V0CgppZiAoa25pdHRpbmcpIHsKICBnZ3NhdmUoCiAgICBoZXJlKCJvdXRwdXRzIiwgIjA3LWtyYWNraGFyZHQiLCAic2NoZW1hX2dhbGxlcnlfb3V0LnBkZiIpLAogICAgcGxvdF9zY2hlbWFzX291dCwKICAgIHdpZHRoID0gMTIsIGhlaWdodCA9IDQsCiAgICBkZXZpY2UgPSBjYWlyb19wZGYsIHVuaXRzID0gImluIiwgZHBpID0gMzAwCiAgKQp9CmBgYAoKYGBge3IgcGxvdC1zY2hlbWEtaW59CnBsb3RfbWVtX2luIDwtIHBsb3RfcmVwcmVzZW50YXRpb24oc2NoZW1hX2V4cGVydHNfaW4sIG1lbV92YWx1ZSkgKwogIGdndGl0bGUoIk1lbW9yaXphdGlvbiIpCgpwbG90X3RyaWFkX2luIDwtIHBsb3RfcmVwcmVzZW50YXRpb24oc2NoZW1hX2V4cGVydHNfaW4sIHRyaWFkX3ZhbHVlKSArCiAgZ2d0aXRsZSgiVHJpYWQgQ29tcGxldGlvbiIpCgpwbG90X2NvbW1faW4gPC0gcGxvdF9yZXByZXNlbnRhdGlvbihzY2hlbWFfZXhwZXJ0c19pbiwgY29tbV92YWx1ZSkgKwogIGdndGl0bGUoIkNvbW11bml0eSBEZXRlY3Rpb24iKQoKcGxvdF9zY2hlbWFzX2luIDwtICgKICBwbG90X2Nob2ljZSB8IHBsb3RfbWVtX2luIHwgcGxvdF90cmlhZF9pbiB8IHBsb3RfY29tbV9pbgopICsKICBwbG90X2Fubm90YXRpb24oCiAgICB0aXRsZSA9ICJBZHZpc29ycyBvYnNlcnZlIGFkdmlzZWVzJyBhZHZpc2VlcyIsCiAgICB0aGVtZSA9IHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1LCBoanVzdCA9IDAuNSkpCiAgKQoKcGxvdF9zY2hlbWFzX2luCgppZiAoa25pdHRpbmcpIHsKICBnZ3NhdmUoCiAgICBoZXJlKCJvdXRwdXRzIiwgIjA3LWtyYWNraGFyZHQiLCAic2NoZW1hX2dhbGxlcnlfaW4ucGRmIiksCiAgICBwbG90X3NjaGVtYXNfaW4sCiAgICB3aWR0aCA9IDEyLCBoZWlnaHQgPSA0LAogICAgZGV2aWNlID0gY2Fpcm9fcGRmLCB1bml0cyA9ICJpbiIsIGRwaSA9IDMwMAogICkKfQpgYGAKCkF0IHRoZSBncm91cC1sZXZlbC4uLiBzY2hlbWFzIG1ha2UgZnJhbmtseSB0ZXJyaWJsZSBwcmVkaWN0aW9ucywgbm8gbWF0dGVyIHdoYXQgd2UgYXNzdW1lIGFib3V0IG9ic2VydmF0aW9ucy4gTm90ZSB0aGF0IGlmIGEgcGFydGljdWxhciBzdWJqZWN0IGlzIHByZWRpY3RlZCB0byBhc2sgYWxsIG90aGVyIG1hbmFnZXJzIGZvciBhZHZpY2UsIHRoZSByb3cgYXNzb2NpYXRlZCB3aXRoIHRoYXQgc3ViamVjdCB3aWxsIGJlIGZpbGxlZCB3aXRoIGEgdmFsdWUgY2xvc2UgdG8gMS8yMD0wLjA1LiBTbyB3ZSBjYW4gc2VlIHRoYXQgdGhlIHRyaWFkIGNvbXBsZXRpb24gc3RyYXRlZ3kgcHJlZGljdHMgdGhhdCBtb3N0IG1hbmFnZXJzIGFyZSBjb25uZWN0ZWQsIGFuZCB0aGUgY29tbXVuaXR5IGRldGVjdGlvbiBzdHJhdGVneSBwcmVkaWN0cyB0aGF0IGxpdGVyYWxseSBhbGwgbWFuYWdlcnMgYXJlIGNvbm5lY3RlZC4gTmVpdGhlciBjb21lcyBldmVuIGEgbGl0dGxlIGJpdCBjbG9zZSB0byB0aGUgYWN0dWFsIGFsbG9jZW50cmljIG5ldHdvcmsgcmVwcmVzZW50YXRpb24uCgoKIyBTdWNjZXNzb3IgcmVwZXNlbnRhdGlvbgoKTGV0J3Mgc2F5IHBlb3BsZSB1c2UgbXVsdGlzdGVwIHJlbGF0aW9uYWwgYWJzdHJhY3Rpb24gdG8gcmVwcmVzZW50IG5ldHdvcmtzLCBhbmQgbGV0J3MgdXNlIHRoZSBTUiB0byBhcHByb3hpbWF0ZSB0aGF0IGtpbmQgb2YgYWJzdHJhY3Rpb24uIFVzaW5nIHRoZSBvYnNlcnZhdGlvbnMgd2UgZ2VuZXJhdGVkIGJlZm9yZSwgbGV0J3MgY3JlYXRlIGxvdHMgb2YgbGVhcm5pbmcgInRyaWFscyIgdG8gdHJhaW4gdGhlIGFsZ29yaXRobS4KCmBgYHtyIGNyZWF0ZS1zci1vYnN9CnNyX29ic2VydmF0aW9uc19hbGwgPC0gb2JzX2VkZ2VsaXN0X2FsbCAlPiUKICAjIENyZWF0ZSBzaW11bGF0ZWQgImxlYXJuaW5nIHRyaWFscyIgdG8gdHJhaW4gYW4gYXN5bXB0b3RpYyBTUgogIGV4cGFuZF9ncmlkKHJlcCA9IDE6MTAwKSAlPiUKICAjIFJhbmRvbWl6ZSAib3JkZXIgb2YgdHJpYWxzIiBwZXIgcmVwZXRpdGlvbgogIGdyb3VwX2J5KHN1Yl9pZCwgcmVwKSAlPiUKICBzbGljZV9zYW1wbGUocHJvcCA9IDEpICU+JQogIHVuZ3JvdXAoKQoKc3Jfb2JzZXJ2YXRpb25zX291dCA8LSBvYnNfZWRnZWxpc3Rfb3V0ICU+JQogIGV4cGFuZF9ncmlkKHJlcCA9IDE6MTAwKSAlPiUKICBncm91cF9ieShzdWJfaWQsIHJlcCkgJT4lCiAgc2xpY2Vfc2FtcGxlKHByb3AgPSAxKSAlPiUKICB1bmdyb3VwKCkKCnNyX29ic2VydmF0aW9uc19pbiA8LSBvYnNfZWRnZWxpc3RfaW4gJT4lCiAgZXhwYW5kX2dyaWQocmVwID0gMToxMDApICU+JQogIGdyb3VwX2J5KHN1Yl9pZCwgcmVwKSAlPiUKICBzbGljZV9zYW1wbGUocHJvcCA9IDEpICU+JQogIHVuZ3JvdXAoKQpgYGAKCkFuZCBub3cgd2UgY2FuIHVzZSB0aG9zZSB0byBidWlsZCBTUnMgYXQgZGlmZmVyZW50IHNjYWxlcy4gV2UnbGwgYXNzdW1lIHRoYXQgZXZlcnkgc3ViamVjdCBpcyB1c2luZyB0aGUgc2FtZSBzdWNjZXNzb3IgaG9yaXpvbi4uLgoKYGBge3IgY29tcHV0ZS1zcn0Kc3JfYWxsIDwtIHNyX29ic2VydmF0aW9uc19hbGwgJT4lCiAgZXhwYW5kX2dyaWQoZ2FtbWEgPSBzZXEoMC4xLCAwLjksIDAuMSksIC4pICU+JQogIGdyb3VwX2J5KHN1Yl9pZCwgZ2FtbWEpICU+JQogIG5lc3QoKSAlPiUKICBtdXRhdGUoCiAgICBzciA9IG1hcDIoCiAgICAgIC54ID0gZGF0YSwgLnkgPSBnYW1tYSwKICAgICAgfmJ1aWxkX3JlcF9zcigueCwgdGhpc19hbHBoYSA9IDAuMSwgdGhpc19nYW1tYSA9IC55KQogICAgKQogICkgJT4lCiAgdW5uZXN0KHNyKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgc2VsZWN0KC1kYXRhKSAlPiUKICBtdXRhdGUoZ2FtbWEgPSBnYW1tYSAqIDEwKSAlPiUKICBwaXZvdF93aWRlcigKICAgIG5hbWVzX2Zyb20gPSBnYW1tYSwKICAgIG5hbWVzX3ByZWZpeCA9ICJzciIsCiAgICB2YWx1ZXNfZnJvbSA9IHNyX3ZhbHVlCiAgKQoKc3Jfb3V0IDwtIHNyX29ic2VydmF0aW9uc19vdXQgJT4lCiAgZXhwYW5kX2dyaWQoZ2FtbWEgPSBzZXEoMC4xLCAwLjksIDAuMSksIC4pICU+JQogIGdyb3VwX2J5KHN1Yl9pZCwgZ2FtbWEpICU+JQogIG5lc3QoKSAlPiUKICBtdXRhdGUoCiAgICBzciA9IG1hcDIoCiAgICAgIC54ID0gZGF0YSwgLnkgPSBnYW1tYSwKICAgICAgfmJ1aWxkX3JlcF9zcigueCwgdGhpc19hbHBoYSA9IDAuMSwgdGhpc19nYW1tYSA9IC55KQogICAgKQogICkgJT4lCiAgdW5uZXN0KHNyKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgc2VsZWN0KC1kYXRhKSAlPiUKICBtdXRhdGUoZ2FtbWEgPSBnYW1tYSAqIDEwKSAlPiUKICBwaXZvdF93aWRlcigKICAgIG5hbWVzX2Zyb20gPSBnYW1tYSwKICAgIG5hbWVzX3ByZWZpeCA9ICJzciIsCiAgICB2YWx1ZXNfZnJvbSA9IHNyX3ZhbHVlCiAgKQoKc3JfaW4gPC0gc3Jfb2JzZXJ2YXRpb25zX2luICU+JQogIGV4cGFuZF9ncmlkKGdhbW1hID0gc2VxKDAuMSwgMC45LCAwLjEpLCAuKSAlPiUKICBncm91cF9ieShzdWJfaWQsIGdhbW1hKSAlPiUKICBuZXN0KCkgJT4lCiAgbXV0YXRlKAogICAgc3IgPSBtYXAyKAogICAgICAueCA9IGRhdGEsIC55ID0gZ2FtbWEsCiAgICAgIH5idWlsZF9yZXBfc3IoLngsIHRoaXNfYWxwaGEgPSAwLjEsIHRoaXNfZ2FtbWEgPSAueSkKICAgICkKICApICU+JQogIHVubmVzdChzcikgJT4lCiAgdW5ncm91cCgpICU+JQogIHNlbGVjdCgtZGF0YSkgJT4lCiAgbXV0YXRlKGdhbW1hID0gZ2FtbWEgKiAxMCkgJT4lCiAgcGl2b3Rfd2lkZXIoCiAgICBuYW1lc19mcm9tID0gZ2FtbWEsCiAgICBuYW1lc19wcmVmaXggPSAic3IiLAogICAgdmFsdWVzX2Zyb20gPSBzcl92YWx1ZQogICkKYGBgCgpMZXQncyBnZXQgYSBzZW5zZSBmb3IgdGhlIHByZWRpY3Rpb25zIHdoZW4gdGhlIFNSIGlzIHRyYWluZWQgb24gb2JzZXJ2YXRpb25zIHRoYXQgZ28gYm90aCB3YXlzLgoKYGBge3IgcGxvdC1zci1hbGx9CnBsb3Rfc3IxX2FsbCA8LSBzcl9hbGwgJT4lCiAgcGxvdF9yZXByZXNlbnRhdGlvbihyZWxhdGlvbl92YWx1ZSA9IHNyMSwgbl9icmVha3MgPSA0KSArCiAgZ2d0aXRsZSgiXHUwM0IzID0gMC4xIikKCnBsb3Rfc3IzX2FsbCA8LSBzcl9hbGwgJT4lCiAgcGxvdF9yZXByZXNlbnRhdGlvbihyZWxhdGlvbl92YWx1ZSA9IHNyMykgKwogIGdndGl0bGUoIlx1MDNCMyA9IDAuMyIpCgpwbG90X3NyNV9hbGwgPC0gc3JfYWxsICU+JQogIHBsb3RfcmVwcmVzZW50YXRpb24ocmVsYXRpb25fdmFsdWUgPSBzcjUpICsKICBnZ3RpdGxlKCJcdTAzQjMgPSAwLjUiKQoKcGxvdF9zcjdfYWxsIDwtIHNyX2FsbCAlPiUKICBwbG90X3JlcHJlc2VudGF0aW9uKHJlbGF0aW9uX3ZhbHVlID0gc3I3KSArCiAgZ2d0aXRsZSgiXHUwM0IzID0gMC43IikKCnBsb3Rfc3I5X2FsbCA8LSBzcl9hbGwgJT4lCiAgcGxvdF9yZXByZXNlbnRhdGlvbihyZWxhdGlvbl92YWx1ZSA9IHNyOSkgKwogIGdndGl0bGUoIlx1MDNCMyA9IDAuOSIpCgpwbG90X3NyX2dhbGxlcnlfYWxsIDwtICgKICBwbG90X2Nob2ljZSArCiAgICBwbG90X3NyMV9hbGwgKyBwbG90X3NyM19hbGwgKyBwbG90X3NyNV9hbGwgKyBwbG90X3NyN19hbGwgKyBwbG90X3NyOV9hbGwKKQoKcGxvdF9zcl9nYWxsZXJ5X2FsbAoKaWYgKGtuaXR0aW5nKSB7CiAgZ2dzYXZlKAogICAgaGVyZSgib3V0cHV0cyIsICIwNy1rcmFja2hhcmR0IiwgInNyX2dhbGxlcnlfYWxsLnBkZiIpLAogICAgcGxvdF9zcl9nYWxsZXJ5X2FsbCwKICAgIHdpZHRoID0gMTIsIGhlaWdodCA9IDgsCiAgICBkZXZpY2UgPSBjYWlyb19wZGYsIHVuaXRzID0gImluIiwgZHBpID0gMzAwCiAgKQp9CmBgYAoKQW5kIG5vdyB3aGVyZSBhZHZpc2VlcyBvYnNlcnZlIHRoZWlyIGFkdmlzb3JzJyBhZHZpc29ycy4uLgoKYGBge3IgcGxvdC1zci1vdXR9CnBsb3Rfc3IxX291dCA8LSBzcl9vdXQgJT4lCiAgcGxvdF9yZXByZXNlbnRhdGlvbihyZWxhdGlvbl92YWx1ZSA9IHNyMSwgbl9icmVha3MgPSA0KSArCiAgZ2d0aXRsZSgiXHUwM0IzID0gMC4xIikKCnBsb3Rfc3IzX291dCA8LSBzcl9vdXQgJT4lCiAgcGxvdF9yZXByZXNlbnRhdGlvbihyZWxhdGlvbl92YWx1ZSA9IHNyMykgKwogIGdndGl0bGUoIlx1MDNCMyA9IDAuMyIpCgpwbG90X3NyNV9vdXQgPC0gc3Jfb3V0ICU+JQogIHBsb3RfcmVwcmVzZW50YXRpb24ocmVsYXRpb25fdmFsdWUgPSBzcjUpICsKICBnZ3RpdGxlKCJcdTAzQjMgPSAwLjUiKQoKcGxvdF9zcjdfb3V0IDwtIHNyX291dCAlPiUKICBwbG90X3JlcHJlc2VudGF0aW9uKHJlbGF0aW9uX3ZhbHVlID0gc3I3KSArCiAgZ2d0aXRsZSgiXHUwM0IzID0gMC43IikKCnBsb3Rfc3I5X291dCA8LSBzcl9vdXQgJT4lCiAgcGxvdF9yZXByZXNlbnRhdGlvbihyZWxhdGlvbl92YWx1ZSA9IHNyOSkgKwogIGdndGl0bGUoIlx1MDNCMyA9IDAuOSIpCgpwbG90X3NyX2dhbGxlcnlfb3V0IDwtICgKICBwbG90X2Nob2ljZSArCiAgICBwbG90X3NyMV9vdXQgKyBwbG90X3NyM19vdXQgKyBwbG90X3NyNV9vdXQgKyBwbG90X3NyN19vdXQgKyBwbG90X3NyOV9vdXQKKQoKcGxvdF9zcl9nYWxsZXJ5X291dAoKaWYgKGtuaXR0aW5nKSB7CiAgZ2dzYXZlKAogICAgaGVyZSgib3V0cHV0cyIsICIwNy1rcmFja2hhcmR0IiwgInNyX2dhbGxlcnlfb3V0LnBkZiIpLAogICAgcGxvdF9zcl9nYWxsZXJ5X291dCwKICAgIHdpZHRoID0gMTIsIGhlaWdodCA9IDgsCiAgICBkZXZpY2UgPSBjYWlyb19wZGYsIHVuaXRzID0gImluIiwgZHBpID0gMzAwCiAgKQp9CmBgYAoKQW5kIGZpbmFsbHkgd2hlcmUgYWR2aXNvcnMgb2JzZXJ2ZSB0aGVpciBhZHZpc2VlcycgYWR2aXNlZXMuLi4KCmBgYHtyIHBsb3Qtc3ItaW59CnBsb3Rfc3IxX2luIDwtIHNyX2luICU+JQogIHBsb3RfcmVwcmVzZW50YXRpb24ocmVsYXRpb25fdmFsdWUgPSBzcjEsIG5fYnJlYWtzID0gNCkgKwogIGdndGl0bGUoIlx1MDNCMyA9IDAuMSIpCgpwbG90X3NyM19pbiA8LSBzcl9pbiAlPiUKICBwbG90X3JlcHJlc2VudGF0aW9uKHJlbGF0aW9uX3ZhbHVlID0gc3IzKSArCiAgZ2d0aXRsZSgiXHUwM0IzID0gMC4zIikKCnBsb3Rfc3I1X2luIDwtIHNyX2luICU+JQogIHBsb3RfcmVwcmVzZW50YXRpb24ocmVsYXRpb25fdmFsdWUgPSBzcjUpICsKICBnZ3RpdGxlKCJcdTAzQjMgPSAwLjUiKQoKcGxvdF9zcjdfaW4gPC0gc3JfaW4gJT4lCiAgcGxvdF9yZXByZXNlbnRhdGlvbihyZWxhdGlvbl92YWx1ZSA9IHNyNykgKwogIGdndGl0bGUoIlx1MDNCMyA9IDAuNyIpCgpwbG90X3NyOV9pbiA8LSBzcl9pbiAlPiUKICBwbG90X3JlcHJlc2VudGF0aW9uKHJlbGF0aW9uX3ZhbHVlID0gc3I5KSArCiAgZ2d0aXRsZSgiXHUwM0IzID0gMC45IikKCnBsb3Rfc3JfZ2FsbGVyeV9pbiA8LSAoCiAgcGxvdF9jaG9pY2UgKwogICAgcGxvdF9zcjFfaW4gKyBwbG90X3NyM19pbiArIHBsb3Rfc3I1X2luICsgcGxvdF9zcjdfaW4gKyBwbG90X3NyOV9pbgopCgpwbG90X3NyX2dhbGxlcnlfaW4KCmlmIChrbml0dGluZykgewogIGdnc2F2ZSgKICAgIGhlcmUoIm91dHB1dHMiLCAiMDcta3JhY2toYXJkdCIsICJzcl9nYWxsZXJ5X2luLnBkZiIpLAogICAgcGxvdF9zcl9nYWxsZXJ5X2luLAogICAgd2lkdGggPSAxMiwgaGVpZ2h0ID0gOCwKICAgIGRldmljZSA9IGNhaXJvX3BkZiwgdW5pdHMgPSAiaW4iLCBkcGkgPSAzMDAKICApCn0KYGBgCgoKIyBTdGF0aXN0aWNhbCB0ZXN0cwoKT2theSwgbm93IHRoYXQgd2UgaGF2ZSBhbGwgb2YgdGhlIHByZWRpY3RlZCBzdHJhdGVnaWVzIGluIGhhbmQsIHdlJ2xsIHdhbnQgdG8gcGVyZm9ybSBzb21lIGZvcm1hbCBzdGF0aXN0aWNhbCB0ZXN0cyB0byB2ZXJpZnkgdGhhdCB0aGUgU1IgaXMgdHJ1bHkgZG9pbmcgdGhlIGJlc3QgYXQgZXhwbGFpbmluZyBzdWJqZWN0cycgbmV0d29yayByZXByZXNlbnRhdGlvbnMuIExldCdzIGNyZWF0ZSBhIGRhdGFmcmFtZSB3aXRoIGFsbCBvZiB0aGUgaW5mbyB3ZSdsbCBuZWVkLgoKYGBge3IgZGVmaW5lLXRlc3QtZGF0YXNldH0KdGVzdF9kYXRhc2V0X2FsbCA8LSBrcmFja2hhcmR0X2FsbG9jZW50cmljICU+JQogIHJlbmFtZShjaG9pY2UgPSBlZGdlKSAlPiUKICBsZWZ0X2pvaW4oc2NoZW1hX2V4cGVydHNfYWxsLCBieSA9IGMoInN1Yl9pZCIsICJmcm9tIiwgInRvIikpICU+JQogIGxlZnRfam9pbihzcl9hbGwsIGJ5ID0gYygic3ViX2lkIiwgImZyb20iLCAidG8iKSkKCnRlc3RfZGF0YXNldF9vdXQgPC0ga3JhY2toYXJkdF9hbGxvY2VudHJpYyAlPiUKICByZW5hbWUoY2hvaWNlID0gZWRnZSkgJT4lCiAgbGVmdF9qb2luKHNjaGVtYV9leHBlcnRzX291dCwgYnkgPSBjKCJzdWJfaWQiLCAiZnJvbSIsICJ0byIpKSAlPiUKICBsZWZ0X2pvaW4oc3Jfb3V0LCBieSA9IGMoInN1Yl9pZCIsICJmcm9tIiwgInRvIikpCgp0ZXN0X2RhdGFzZXRfaW4gPC0ga3JhY2toYXJkdF9hbGxvY2VudHJpYyAlPiUKICByZW5hbWUoY2hvaWNlID0gZWRnZSkgJT4lCiAgbGVmdF9qb2luKHNjaGVtYV9leHBlcnRzX2luLCBieSA9IGMoInN1Yl9pZCIsICJmcm9tIiwgInRvIikpICU+JQogIGxlZnRfam9pbihzcl9pbiwgYnkgPSBjKCJzdWJfaWQiLCAiZnJvbSIsICJ0byIpKQpgYGAKCldlJ2xsIGRvIGFsbCBvZiB0aGUgc3RhdGlzdGljYWwgdGVzdHMgZm9yIHRoZSAib2JzZXJ2YXRpb25zIGdvIGJvdGggd2F5cyIgbW9kZWxzLiBOb3RlIHRoYXQgd2UgY2FuJ3QgYWN0dWFsbHkgZXN0aW1hdGUgYSBtb2RlbCBmb3IgY29tbXVuaXR5IGRldGVjdGlvbiwgYXMgdGhpcyBzdHJhdGVneSBwcmVkaWN0cyB0aGF0IGV2ZXJ5b25lIGlzIGNvbm5lY3RlZCB0byBldmVyeW9uZS4KCmBgYHtyIHRlc3Qtb2JzLWFsbH0KdGVzdF9tZW1fYWxsIDwtIHRlc3RfZGF0YXNldF9hbGwgJT4lCiAgZ2xtZXIoCiAgICBjaG9pY2UgfiBtZW1fdmFsdWUgKyAoMSArIG1lbV92YWx1ZSB8IHN1Yl9pZCksCiAgICBmYW1pbHkgPSAiYmlub21pYWwiLCBkYXRhID0gLgogICkKCnRlc3RfdHJpYWRfYWxsIDwtIHRlc3RfZGF0YXNldF9hbGwgJT4lCiAgZ2xtZXIoCiAgICBjaG9pY2UgfiBtZW1fdmFsdWUgKyB0cmlhZF92YWx1ZSArICgxICsgdHJpYWRfdmFsdWUgfCBzdWJfaWQpLAogICAgZmFtaWx5ID0gImJpbm9taWFsIiwgZGF0YSA9IC4KICApCgojIHRlc3RfY29tbV9hbGwgPC0gdGVzdF9kYXRhc2V0X2FsbCAlPiUKIyAgIGdsbWVyKAojICAgICBjaG9pY2UgfiBtZW1fdmFsdWUgKyBjb21tX3ZhbHVlICsgKDEgKyBjb21tX3ZhbHVlIHwgc3ViX2lkKSwKIyAgICAgZmFtaWx5ID0gImJpbm9taWFsIiwgZGF0YSA9IC4KIyAgICkKCnRlc3Rfc3IxX2FsbCA8LSB0ZXN0X2RhdGFzZXRfYWxsICU+JQogIGdsbWVyKAogICAgY2hvaWNlIH4gbWVtX3ZhbHVlICsgc3IxICsgKDEgKyBzcjEgfCBzdWJfaWQpLAogICAgZmFtaWx5ID0gImJpbm9taWFsIiwgZGF0YSA9IC4KICApCgp0ZXN0X3NyMl9hbGwgPC0gdGVzdF9kYXRhc2V0X2FsbCAlPiUKICBnbG1lcigKICAgIGNob2ljZSB+IG1lbV92YWx1ZSArIHNyMiArICgxICsgc3IyIHwgc3ViX2lkKSwKICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIGRhdGEgPSAuCiAgKQoKdGVzdF9zcjNfYWxsIDwtIHRlc3RfZGF0YXNldF9hbGwgJT4lCiAgZ2xtZXIoCiAgICBjaG9pY2UgfiBtZW1fdmFsdWUgKyBzcjMgKyAoMSArIHNyMyB8IHN1Yl9pZCksCiAgICBmYW1pbHkgPSAiYmlub21pYWwiLCBkYXRhID0gLgogICkKCnRlc3Rfc3I0X2FsbCA8LSB0ZXN0X2RhdGFzZXRfYWxsICU+JQogIGdsbWVyKAogICAgY2hvaWNlIH4gbWVtX3ZhbHVlICsgc3I0ICsgKDEgKyBzcjQgfCBzdWJfaWQpLAogICAgZmFtaWx5ID0gImJpbm9taWFsIiwgZGF0YSA9IC4KICApCgp0ZXN0X3NyNV9hbGwgPC0gdGVzdF9kYXRhc2V0X2FsbCAlPiUKICBnbG1lcigKICAgIGNob2ljZSB+IG1lbV92YWx1ZSArIHNyNSArICgxICsgc3I1IHwgc3ViX2lkKSwKICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIGRhdGEgPSAuCiAgKQoKdGVzdF9zcjZfYWxsIDwtIHRlc3RfZGF0YXNldF9hbGwgJT4lCiAgZ2xtZXIoCiAgICBjaG9pY2UgfiBtZW1fdmFsdWUgKyBzcjYgKyAoMSArIHNyNiB8IHN1Yl9pZCksCiAgICBmYW1pbHkgPSAiYmlub21pYWwiLCBkYXRhID0gLgogICkKCnRlc3Rfc3I3X2FsbCA8LSB0ZXN0X2RhdGFzZXRfYWxsICU+JQogIGdsbWVyKAogICAgY2hvaWNlIH4gbWVtX3ZhbHVlICsgc3I3ICsgKDEgKyBzcjcgfCBzdWJfaWQpLAogICAgZmFtaWx5ID0gImJpbm9taWFsIiwgZGF0YSA9IC4KICApCgp0ZXN0X3NyOF9hbGwgPC0gdGVzdF9kYXRhc2V0X2FsbCAlPiUKICBnbG1lcigKICAgIGNob2ljZSB+IG1lbV92YWx1ZSArIHNyOCArICgxICsgc3I4IHwgc3ViX2lkKSwKICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIGRhdGEgPSAuCiAgKQoKdGVzdF9zcjlfYWxsIDwtIHRlc3RfZGF0YXNldF9hbGwgJT4lCiAgZ2xtZXIoCiAgICBjaG9pY2UgfiBtZW1fdmFsdWUgKyBzcjkgKyAoMSArIHNyOSB8IHN1Yl9pZCksCiAgICBmYW1pbHkgPSAiYmlub21pYWwiLCBkYXRhID0gLgogICkKYGBgCgpNb3Zpbmcgb24gdG8gdGhlICJhZHZpc2VlcyBvYnNlcnZlIGFkdmlzb3JzJyBhZHZpc29ycyIgbW9kZWxzLgoKYGBge3IgdGVzdC1vYnMtb3V0fQp0ZXN0X21lbV9vdXQgPC0gdGVzdF9kYXRhc2V0X291dCAlPiUKICBnbG1lcigKICAgIGNob2ljZSB+IG1lbV92YWx1ZSArICgxICsgbWVtX3ZhbHVlIHwgc3ViX2lkKSwKICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIGRhdGEgPSAuCiAgKQoKdGVzdF90cmlhZF9vdXQgPC0gdGVzdF9kYXRhc2V0X291dCAlPiUKICBnbG1lcigKICAgIGNob2ljZSB+IG1lbV92YWx1ZSArIHRyaWFkX3ZhbHVlICsgKDEgKyB0cmlhZF92YWx1ZSB8IHN1Yl9pZCksCiAgICBmYW1pbHkgPSAiYmlub21pYWwiLCBkYXRhID0gLgogICkKCnRlc3RfY29tbV9vdXQgPC0gdGVzdF9kYXRhc2V0X291dCAlPiUKICBnbG1lcigKICAgIGNob2ljZSB+IG1lbV92YWx1ZSArIGNvbW1fdmFsdWUgKyAoMSArIGNvbW1fdmFsdWUgfCBzdWJfaWQpLAogICAgZmFtaWx5ID0gImJpbm9taWFsIiwgZGF0YSA9IC4KICApCgp0ZXN0X3NyMV9vdXQgPC0gdGVzdF9kYXRhc2V0X291dCAlPiUKICBnbG1lcigKICAgIGNob2ljZSB+IG1lbV92YWx1ZSArIHNyMSArICgxICsgc3IxIHwgc3ViX2lkKSwKICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIGRhdGEgPSAuCiAgKQoKdGVzdF9zcjJfb3V0IDwtIHRlc3RfZGF0YXNldF9vdXQgJT4lCiAgZ2xtZXIoCiAgICBjaG9pY2UgfiBtZW1fdmFsdWUgKyBzcjIgKyAoMSArIHNyMiB8IHN1Yl9pZCksCiAgICBmYW1pbHkgPSAiYmlub21pYWwiLCBkYXRhID0gLgogICkKCnRlc3Rfc3IzX291dCA8LSB0ZXN0X2RhdGFzZXRfb3V0ICU+JQogIGdsbWVyKAogICAgY2hvaWNlIH4gbWVtX3ZhbHVlICsgc3IzICsgKDEgKyBzcjMgfCBzdWJfaWQpLAogICAgZmFtaWx5ID0gImJpbm9taWFsIiwgZGF0YSA9IC4KICApCgp0ZXN0X3NyNF9vdXQgPC0gdGVzdF9kYXRhc2V0X291dCAlPiUKICBnbG1lcigKICAgIGNob2ljZSB+IG1lbV92YWx1ZSArIHNyNCArICgxICsgc3I0IHwgc3ViX2lkKSwKICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIGRhdGEgPSAuCiAgKQoKdGVzdF9zcjVfb3V0IDwtIHRlc3RfZGF0YXNldF9vdXQgJT4lCiAgZ2xtZXIoCiAgICBjaG9pY2UgfiBtZW1fdmFsdWUgKyBzcjUgKyAoMSArIHNyNSB8IHN1Yl9pZCksCiAgICBmYW1pbHkgPSAiYmlub21pYWwiLCBkYXRhID0gLgogICkKCnRlc3Rfc3I2X291dCA8LSB0ZXN0X2RhdGFzZXRfb3V0ICU+JQogIGdsbWVyKAogICAgY2hvaWNlIH4gbWVtX3ZhbHVlICsgc3I2ICsgKDEgKyBzcjYgfCBzdWJfaWQpLAogICAgZmFtaWx5ID0gImJpbm9taWFsIiwgZGF0YSA9IC4KICApCgp0ZXN0X3NyN19vdXQgPC0gdGVzdF9kYXRhc2V0X291dCAlPiUKICBnbG1lcigKICAgIGNob2ljZSB+IG1lbV92YWx1ZSArIHNyNyArICgxICsgc3I3IHwgc3ViX2lkKSwKICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIGRhdGEgPSAuCiAgKQoKdGVzdF9zcjhfb3V0IDwtIHRlc3RfZGF0YXNldF9vdXQgJT4lCiAgZ2xtZXIoCiAgICBjaG9pY2UgfiBtZW1fdmFsdWUgKyBzcjggKyAoMSArIHNyOCB8IHN1Yl9pZCksCiAgICBmYW1pbHkgPSAiYmlub21pYWwiLCBkYXRhID0gLgogICkKCnRlc3Rfc3I5X291dCA8LSB0ZXN0X2RhdGFzZXRfb3V0ICU+JQogIGdsbWVyKAogICAgY2hvaWNlIH4gbWVtX3ZhbHVlICsgc3I5ICsgKDEgKyBzcjkgfCBzdWJfaWQpLAogICAgZmFtaWx5ID0gImJpbm9taWFsIiwgZGF0YSA9IC4KICApCmBgYAoKRmluYWxseSwgdGhlICJhZHZpc29ycyBvYnNlcnZlIGFkdmlzZWVzJyBhZHZpc2VlcyIgbW9kZWxzLiBPbmNlIGFnYWluLCB3ZSBjYW4ndCBlc3RpbWF0ZSBhIG1vZGVsIGZvciBjb21tdW5pdHkgZGV0ZWN0aW9uLCBhcyB0aGlzIHN0cmF0ZWd5IHByZWRpY3RzIHRoYXQgZXZlcnlvbmUgaXMgY29ubmVjdGVkIHRvIGV2ZXJ5b25lLgoKYGBge3IgdGVzdC1vYnMtaW59CnRlc3RfbWVtX2luIDwtIHRlc3RfZGF0YXNldF9pbiAlPiUKICBnbG1lcigKICAgIGNob2ljZSB+IG1lbV92YWx1ZSArICgxICsgbWVtX3ZhbHVlIHwgc3ViX2lkKSwKICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIGRhdGEgPSAuCiAgKQoKdGVzdF90cmlhZF9pbiA8LSB0ZXN0X2RhdGFzZXRfaW4gJT4lCiAgZ2xtZXIoCiAgICBjaG9pY2UgfiBtZW1fdmFsdWUgKyB0cmlhZF92YWx1ZSArICgxICsgdHJpYWRfdmFsdWUgfCBzdWJfaWQpLAogICAgZmFtaWx5ID0gImJpbm9taWFsIiwgZGF0YSA9IC4KICApCgojIHRlc3RfY29tbV9pbiA8LSB0ZXN0X2RhdGFzZXRfaW4gJT4lCiMgICBnbG1lcigKIyAgICAgY2hvaWNlIH4gbWVtX3ZhbHVlICsgY29tbV92YWx1ZSArICgxICsgY29tbV92YWx1ZSB8IHN1Yl9pZCksCiMgICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIGRhdGEgPSAuCiMgICApCgp0ZXN0X3NyMV9pbiA8LSB0ZXN0X2RhdGFzZXRfaW4gJT4lCiAgZ2xtZXIoCiAgICBjaG9pY2UgfiBtZW1fdmFsdWUgKyBzcjEgKyAoMSArIHNyMSB8IHN1Yl9pZCksCiAgICBmYW1pbHkgPSAiYmlub21pYWwiLCBkYXRhID0gLgogICkKCnRlc3Rfc3IyX2luIDwtIHRlc3RfZGF0YXNldF9pbiAlPiUKICBnbG1lcigKICAgIGNob2ljZSB+IG1lbV92YWx1ZSArIHNyMiArICgxICsgc3IyIHwgc3ViX2lkKSwKICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIGRhdGEgPSAuCiAgKQoKdGVzdF9zcjNfaW4gPC0gdGVzdF9kYXRhc2V0X2luICU+JQogIGdsbWVyKAogICAgY2hvaWNlIH4gbWVtX3ZhbHVlICsgc3IzICsgKDEgKyBzcjMgfCBzdWJfaWQpLAogICAgZmFtaWx5ID0gImJpbm9taWFsIiwgZGF0YSA9IC4KICApCgp0ZXN0X3NyNF9pbiA8LSB0ZXN0X2RhdGFzZXRfaW4gJT4lCiAgZ2xtZXIoCiAgICBjaG9pY2UgfiBtZW1fdmFsdWUgKyBzcjQgKyAoMSArIHNyNCB8IHN1Yl9pZCksCiAgICBmYW1pbHkgPSAiYmlub21pYWwiLCBkYXRhID0gLgogICkKCnRlc3Rfc3I1X2luIDwtIHRlc3RfZGF0YXNldF9pbiAlPiUKICBnbG1lcigKICAgIGNob2ljZSB+IG1lbV92YWx1ZSArIHNyNSArICgxICsgc3I1IHwgc3ViX2lkKSwKICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIGRhdGEgPSAuCiAgKQoKdGVzdF9zcjZfaW4gPC0gdGVzdF9kYXRhc2V0X2luICU+JQogIGdsbWVyKAogICAgY2hvaWNlIH4gbWVtX3ZhbHVlICsgc3I2ICsgKDEgKyBzcjYgfCBzdWJfaWQpLAogICAgZmFtaWx5ID0gImJpbm9taWFsIiwgZGF0YSA9IC4KICApCgp0ZXN0X3NyN19pbiA8LSB0ZXN0X2RhdGFzZXRfaW4gJT4lCiAgZ2xtZXIoCiAgICBjaG9pY2UgfiBtZW1fdmFsdWUgKyBzcjcgKyAoMSArIHNyNyB8IHN1Yl9pZCksCiAgICBmYW1pbHkgPSAiYmlub21pYWwiLCBkYXRhID0gLgogICkKCnRlc3Rfc3I4X2luIDwtIHRlc3RfZGF0YXNldF9pbiAlPiUKICBnbG1lcigKICAgIGNob2ljZSB+IG1lbV92YWx1ZSArIHNyOCArICgxICsgc3I4IHwgc3ViX2lkKSwKICAgIGZhbWlseSA9ICJiaW5vbWlhbCIsIGRhdGEgPSAuCiAgKQoKdGVzdF9zcjlfaW4gPC0gdGVzdF9kYXRhc2V0X2luICU+JQogIGdsbWVyKAogICAgY2hvaWNlIH4gbWVtX3ZhbHVlICsgc3I5ICsgKDEgKyBzcjkgfCBzdWJfaWQpLAogICAgZmFtaWx5ID0gImJpbm9taWFsIiwgZGF0YSA9IC4KICApCmBgYAoKT2YgYWxsIG9mIHRoZXNlIG1vZGVscywgd2hpY2ggaGFzIHRoZSAiYmVzdCIgZml0LCBiYXNlZCBvbiBCSUM/CgpgYGB7ciBnb29kbmVzcy1vZi1maXR9CiMgV2hpY2ggaGFzIHRoZSBiZXN0ICJnb29kbmVzcy1vZi1maXQiPwpnb29kbmVzc19vZl9maXQgPC0gYmluZF9yb3dzKAogICMgQWxsOiBnb2VzIGJvdGggd2F5cwogIGdsYW5jZSh0ZXN0X21lbV9hbGwpICU+JSBtdXRhdGUobW9kZWwgPSAibWVtX2FsbCIpLAogIGdsYW5jZSh0ZXN0X3RyaWFkX2FsbCkgJT4lIG11dGF0ZShtb2RlbCA9ICJ0cmlhZF9hbGwiKSwKICBnbGFuY2UodGVzdF9zcjFfYWxsKSAlPiUgbXV0YXRlKG1vZGVsID0gInNyMV9hbGwiKSwKICBnbGFuY2UodGVzdF9zcjJfYWxsKSAlPiUgbXV0YXRlKG1vZGVsID0gInNyMl9hbGwiKSwKICBnbGFuY2UodGVzdF9zcjNfYWxsKSAlPiUgbXV0YXRlKG1vZGVsID0gInNyM19hbGwiKSwKICBnbGFuY2UodGVzdF9zcjRfYWxsKSAlPiUgbXV0YXRlKG1vZGVsID0gInNyNF9hbGwiKSwKICBnbGFuY2UodGVzdF9zcjVfYWxsKSAlPiUgbXV0YXRlKG1vZGVsID0gInNyNV9hbGwiKSwKICBnbGFuY2UodGVzdF9zcjZfYWxsKSAlPiUgbXV0YXRlKG1vZGVsID0gInNyNl9hbGwiKSwKICBnbGFuY2UodGVzdF9zcjdfYWxsKSAlPiUgbXV0YXRlKG1vZGVsID0gInNyN19hbGwiKSwKICBnbGFuY2UodGVzdF9zcjhfYWxsKSAlPiUgbXV0YXRlKG1vZGVsID0gInNyOF9hbGwiKSwKICBnbGFuY2UodGVzdF9zcjlfYWxsKSAlPiUgbXV0YXRlKG1vZGVsID0gInNyOV9hbGwiKSwKICAjIE91dDogYWR2aXNvcnMgb2YgYWR2aXNvcnMKICBnbGFuY2UodGVzdF9tZW1fb3V0KSAlPiUgbXV0YXRlKG1vZGVsID0gIm1lbV9vdXQiKSwKICBnbGFuY2UodGVzdF90cmlhZF9vdXQpICU+JSBtdXRhdGUobW9kZWwgPSAidHJpYWRfb3V0IiksCiAgZ2xhbmNlKHRlc3RfY29tbV9vdXQpICU+JSBtdXRhdGUobW9kZWwgPSAiY29tbV9vdXQiKSwKICBnbGFuY2UodGVzdF9zcjFfb3V0KSAlPiUgbXV0YXRlKG1vZGVsID0gInNyMV9vdXQiKSwKICBnbGFuY2UodGVzdF9zcjJfb3V0KSAlPiUgbXV0YXRlKG1vZGVsID0gInNyMl9vdXQiKSwKICBnbGFuY2UodGVzdF9zcjNfb3V0KSAlPiUgbXV0YXRlKG1vZGVsID0gInNyM19vdXQiKSwKICBnbGFuY2UodGVzdF9zcjRfb3V0KSAlPiUgbXV0YXRlKG1vZGVsID0gInNyNF9vdXQiKSwKICBnbGFuY2UodGVzdF9zcjVfb3V0KSAlPiUgbXV0YXRlKG1vZGVsID0gInNyNV9vdXQiKSwKICBnbGFuY2UodGVzdF9zcjZfb3V0KSAlPiUgbXV0YXRlKG1vZGVsID0gInNyNl9vdXQiKSwKICBnbGFuY2UodGVzdF9zcjdfb3V0KSAlPiUgbXV0YXRlKG1vZGVsID0gInNyN19vdXQiKSwKICBnbGFuY2UodGVzdF9zcjhfb3V0KSAlPiUgbXV0YXRlKG1vZGVsID0gInNyOF9vdXQiKSwKICBnbGFuY2UodGVzdF9zcjlfb3V0KSAlPiUgbXV0YXRlKG1vZGVsID0gInNyOV9vdXQiKSwKICAjIEluOiBhZHZpc2VlcyBvZiBhZHZpc2VlcwogIGdsYW5jZSh0ZXN0X21lbV9pbikgJT4lIG11dGF0ZShtb2RlbCA9ICJtZW1faW4iKSwKICBnbGFuY2UodGVzdF90cmlhZF9pbikgJT4lIG11dGF0ZShtb2RlbCA9ICJ0cmlhZF9pbiIpLAogIGdsYW5jZSh0ZXN0X3NyMV9pbikgJT4lIG11dGF0ZShtb2RlbCA9ICJzcjFfaW4iKSwKICBnbGFuY2UodGVzdF9zcjJfaW4pICU+JSBtdXRhdGUobW9kZWwgPSAic3IyX2luIiksCiAgZ2xhbmNlKHRlc3Rfc3IzX2luKSAlPiUgbXV0YXRlKG1vZGVsID0gInNyM19pbiIpLAogIGdsYW5jZSh0ZXN0X3NyNF9pbikgJT4lIG11dGF0ZShtb2RlbCA9ICJzcjRfaW4iKSwKICBnbGFuY2UodGVzdF9zcjVfaW4pICU+JSBtdXRhdGUobW9kZWwgPSAic3I1X2luIiksCiAgZ2xhbmNlKHRlc3Rfc3I2X2luKSAlPiUgbXV0YXRlKG1vZGVsID0gInNyNl9pbiIpLAogIGdsYW5jZSh0ZXN0X3NyN19pbikgJT4lIG11dGF0ZShtb2RlbCA9ICJzcjdfaW4iKSwKICBnbGFuY2UodGVzdF9zcjhfaW4pICU+JSBtdXRhdGUobW9kZWwgPSAic3I4X2luIiksCiAgZ2xhbmNlKHRlc3Rfc3I5X2luKSAlPiUgbXV0YXRlKG1vZGVsID0gInNyOV9pbiIpLAopICU+JQogIHNlbGVjdChtb2RlbCwgZXZlcnl0aGluZygpKSAlPiUKICBhcnJhbmdlKEJJQykgJT4lCiAgIyBNYWtlIHRoaXMgYSBsaXR0bGUgbW9yZSBodW1hbi1yZWFkYWJsZQogIHNlcGFyYXRlKG1vZGVsLCBpbnRvID0gYygibW9kZWwiLCAiZGlyZWN0aW9uIikpICU+JQogIG11dGF0ZSgKICAgIGRpcmVjdGlvbiA9IGNhc2Vfd2hlbigKICAgICAgZGlyZWN0aW9uID09ICJvdXQiIH4gImFkdmlzZWUgb2JzZXJ2ZXMgYWR2aXNvciBvZiBhZHZpc29yIiwKICAgICAgZGlyZWN0aW9uID09ICJpbiIgfiAiYWR2aXNvciBvYnNlcnZlcyBhZHZpc2VlIG9mIGFkdmlzZWUiLAogICAgICBkaXJlY3Rpb24gPT0gImFsbCIgfiAiYm90aCB3YXlzIgogICAgKQogICkKCmdvb2RuZXNzX29mX2ZpdCAlPiUKICBtdXRhdGUoCiAgICBtb2RlbCA9IGZjdF9yZWxldmVsKAogICAgICBtb2RlbCwKICAgICAgInNyMSIsICJzcjIiLCAic3IzIiwgInNyNCIsICJzcjUiLCAic3I2IiwgInNyNyIsICJzcjgiLCAic3I5IiwKICAgICAgIm1lbSIsICJ0cmlhZCIsICJjb21tIgogICAgKQogICkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gbW9kZWwsIHkgPSBCSUMsIGNvbG9yID0gZGlyZWN0aW9uKSkgKwogIGdnICsKICBnZW9tX3BvaW50KCkgKwogIGdndGl0bGUoIk1vZGVsIGdvb2RuZXNzLW9mLWZpdCIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCmdvb2RuZXNzX29mX2ZpdCAlPiUKICBrYWJsZSgpCmBgYAoKTGV0J3MgdGFrZSBhIGxvb2sgYXQgdGhlIGJlc3QtZml0dGluZyBtb2RlbCBlc3RpbWF0ZXM6CgpgYGB7ciBiZXN0LW1vZGVsfQp0ZXN0X3NyN19vdXQgJT4lCiAgdGlkeShjb25mLmludCA9IFRSVUUpICU+JQogIGthYmxlKCkKCnZpZih0ZXN0X3NyN19vdXQpCmBgYAoKCgojIFNSIGNlbnRyYWxpdHkKCkNhbiB0aGUgYmVzdC1maXR0aW5nIFNSIGV4cGxhaW4gYW4gaW5kaXZpZHVhbCdzIHBlcmNlcHRpb25zIG9mIG90aGVyIG5ldHdvcmsgbWVtYmVycycgY2VudHJhbGl0eT8KCmBgYHtyIGRlZi1zci1jZW50cmFsaXR5fQpzcl9jZW50cmFsaXR5IDwtIHNyX291dCAlPiUKICAjIFNSIGNlbnRyYWxpdHkgZnJvbSBiZXN0IHZhcmlhbnQKICBmaWx0ZXIoZnJvbSAhPSB0bykgJT4lCiAgZ3JvdXBfYnkoc3ViX2lkLCBub2RlX2lkID0gdG8pICU+JQogIHN1bW1hcmlzZShzcl9jZW50cmFsaXR5ID0gbWVhbihzcjcpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUKICAjIFBlcmNlaXZlZCBjZW50cmFsaXR5CiAgbGVmdF9qb2luKAogICAga3JhY2toYXJkdF9hbGxvY2VudHJpYyAlPiUKICAgICAgZ3JvdXBfYnkoc3ViX2lkLCBub2RlX2lkID0gdG8pICU+JQogICAgICBzdW1tYXJpc2UocGVyY2VpdmVkX2NlbnRyYWxpdHkgPSBtZWFuKGVkZ2UpLCAuZ3JvdXBzID0gImRyb3AiKSwKICAgIGJ5ID0gYygic3ViX2lkIiwgIm5vZGVfaWQiKQogICkKYGBgCgpUbyBhbnN3ZXIgdGhpcywgd2UnbGwgZG8gYSByYW5kb20tZWZmZWN0cyBhbmFseXNpcyB3aGVyZSB3ZSB0YWtlIGVhY2ggaW5kaXZpZHVhbCdzIGlkaW9zeW5jcmF0aWMgbWVudGFsIHJlcHJlc2VudGF0aW9uIG9mIHRoZWlyIG5ldHdvcmssIHRoZW4gcmFuay1jb3JyZWxhdGUgaXQgd2l0aCB0aGUgU1IncyBpbmRpdmlkdWFsLWxldmVsIHByZWRpY3Rpb25zLgoKYGBge3IgdGVzdC1zci1jZW50cmFsaXR5fQpzcl9jZW50cmFsaXR5X2NvcnIgPC0gc3JfY2VudHJhbGl0eSAlPiUKICBncm91cF9ieShzdWJfaWQpICU+JQogIG5lc3QoKSAlPiUKICBtdXRhdGUoCiAgICBzcGVhcm1hbiA9IG1hcF9kYmwoCiAgICAgIC54ID0gZGF0YSwKICAgICAgLmYgPSB+d2l0aCgKICAgICAgICAueCwgY29yKHNyX2NlbnRyYWxpdHksIHBlcmNlaXZlZF9jZW50cmFsaXR5LCBtZXRob2QgPSAic3BlYXJtYW4iKQogICAgICApCiAgICApCiAgKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgc2VsZWN0KC1kYXRhKQoKc3JfY2VudHJhbGl0eV9jb3JyICU+JQogIG11dGF0ZShzcGVhcm1hbiA9IGF0YW5oKHNwZWFybWFuKSkgJT4lCiAgc2VsZWN0KHNwZWFybWFuKSAlPiUKICBkZWZyYW1lKCkgJT4lCiAgdC50ZXN0KCkgJT4lCiAgdGlkeSgpICU+JQogIGthYmxlKAogICAgY2FwdGlvbiA9IHN0cl9jKAogICAgICAidC10ZXN0IG9mIHRoZSBhdmVyYWdlIFNwZWFybWFuIGNvcnJlbGF0aW9uIGJldHdlZW4gcGVyY2VpdmVkIGFuZCAiLAogICAgICAiU1ItcHJlZGljdGVkIGNlbnRyYWxpdHkgKHotdHJhbnNmb3JtZWQpIgogICAgKQogICkKCnNyX2NlbnRyYWxpdHlfY29yciAlPiUKICBzdW1tYXJpc2UobWVhbl9zcGVhcm1hbiA9IG1lYW4oc3BlYXJtYW4pKSAlPiUKICBrYWJsZSgpCmBgYAoKTGV0J3MgdHJ5IHRvIHZpc3VhbGl6ZSB0aGVzZSByZXN1bHRzIGluIGFuIGludHVpdGl2ZSBmb3JtYXQuCgpgYGB7ciBwbG90LXNyLWNlbnRyYWxpdHl9CnBsb3Rfc3JfY2VudHJhbGl0eV9ncm91cCA8LSBzcl9jZW50cmFsaXR5ICU+JQogICMgR2V0IGVhY2ggc3ViamVjdCdzIHJhbmstb3JkZXJlZCBwZXJjZWl2ZWQgYW5kIFNSLXByZWRpY3RlZCBjZW50cmFsaXR5CiAgZ3JvdXBfYnkoc3ViX2lkKSAlPiUKICBtdXRhdGUoYWNyb3NzKGVuZHNfd2l0aCgiX2NlbnRyYWxpdHkiKSwgfnJhbmsoLngsIHRpZXMubWV0aG9kID0gIm1pbiIpKSkgJT4lCiAgdW5ncm91cCgpICU+JQogICMgQXZlcmFnZSBhY3Jvc3Mgc3ViamVjdHMgdG8gZ2V0IGdyb3VwLWxldmVsIHJlc3VsdHMKICBncm91cF9ieShub2RlX2lkKSAlPiUKICBzdW1tYXJpc2UoYWNyb3NzKGVuZHNfd2l0aCgiX2NlbnRyYWxpdHkiKSwgbWVhbikpICU+JQogICMgRm9yIGNvbG9yLWNvZGluZyB0d28gcGFpcnMgb2YgbWFuYWdlcnMgd2l0aCBlcXVpdmFsZW50IGRlZ3JlZSBjZW50cmFsaXR5LAogICMgYnV0IGRpZmZlcmVudCBwZXJjZWl2ZWQgY2VudHJhbGl0eQogIG11dGF0ZSgKICAgIGNvbG9yY29kZSA9IGNhc2Vfd2hlbigKICAgICAgbm9kZV9pZCAlaW4lIGMoMSwgNykgfiAiYSIsCiAgICAgIG5vZGVfaWQgJWluJSBjKDE4LCAyMSkgfiAiYiIKICAgICkKICApICU+JQogIGdncGxvdChhZXMoeD1wZXJjZWl2ZWRfY2VudHJhbGl0eSwgeT1zcl9jZW50cmFsaXR5KSkgKwogIGdnICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2xvciA9ICJibGFjayIpICsKICBnZW9tX2xhYmVsKGFlcyhsYWJlbCA9IG5vZGVfaWQsIGZpbGwgPSBjb2xvcmNvZGUpLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI2E2Y2VlMyIsICIjYjJkZjhhIiksIG5hLnZhbHVlID0gImdyZXk5NSIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobmFtZSA9ICJQZXJjZWl2ZWQgY2VudHJhbGl0eSAocmFuay1vcmRlcmVkKSIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobmFtZSA9ICJTUiBjZW50cmFsaXR5IChyYW5rLW9yZGVyZWQpIikgKwogIGdndGl0bGUoIlBlcmNlaXZlZCB2cyBTdWNjZXNzb3IgQ2VudHJhbGl0eSAoR3JvdXAtTGV2ZWwpIikKCnBsb3Rfc3JfY2VudHJhbGl0eV9ncm91cAoKcGxvdF9zcl9jZW50cmFsaXR5X2luZGl2aWR1YWwgPC0gc3JfY2VudHJhbGl0eSAlPiUKICAjIEdldCBlYWNoIHN1YmplY3QncyByYW5rLW9yZGVyZWQgcGVyY2VpdmVkIGFuZCBTUi1wcmVkaWN0ZWQgY2VudHJhbGl0eQogIGdyb3VwX2J5KHN1Yl9pZCkgJT4lCiAgbXV0YXRlKGFjcm9zcyhlbmRzX3dpdGgoIl9jZW50cmFsaXR5IiksIH5yYW5rKC54LCB0aWVzLm1ldGhvZCA9ICJtaW4iKSkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICAjIEZvcm1hdHRpbmcgZm9yIHBsb3R0aW5nCiAgcGl2b3RfbG9uZ2VyKAogICAgZW5kc193aXRoKCJfY2VudHJhbGl0eSIpLAogICAgbmFtZXNfdG8gPSAibWV0cmljIiwKICAgIHZhbHVlc190byA9ICJjZW50cmFsaXR5IgogICkgJT4lCiAgbXV0YXRlKAogICAgbm9kZV9pZCA9IGZhY3Rvcihub2RlX2lkKSwKICAgIHN1Yl9pZCA9IHN0cl9wYWQoc3ViX2lkLCB3aWR0aCA9IDIsIHNpZGUgPSAibGVmdCIsIHBhZCA9ICIwIiksCiAgICBzdWJfaWQgPSBzdHJfYygiTWFuYWdlciAiLCBzdWJfaWQpCiAgKSAlPiUKICBnZ3Bsb3QoYWVzKHg9bm9kZV9pZCwgeT1jZW50cmFsaXR5LCBmaWxsPW1ldHJpYykpICsKICBmYWNldF93cmFwKH5zdWJfaWQsIG5yb3cgPSAzKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiaWRlbnRpdHkiLCBjb2xvciA9ICJibGFjayIsIGFscGhhID0gMC41KSArCiAgY29vcmRfcG9sYXIoKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2QoCiAgICBuYW1lID0gIkNlbnRyYWxpdHkiLAogICAgbGFiZWxzID0gYygiUGVyY2VpdmVkIChFbXBpcmljYWwpIiwgIlN1Y2Nlc3NvciBSZXByZXNlbnRhdGlvbiAoU2ltdWxhdGVkKSIpCiAgKSArCiAgZ2d0aXRsZSgiUGVyY2VpdmVkIHZzIFN1Y2Nlc3NvciBDZW50cmFsaXR5IChJbmRpdmlkdWFsLUxldmVsKSIpICsKICB0aGVtZV9idygpICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxMyksCiAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTEpLAogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLnNwYWNpbmcgPSB1bml0KDAuNzUsICJsaW5lcyIpLAogICAgbGVnZW5kLmJveC5zcGFjaW5nID0gdW5pdCgwLjUsICJsaW5lcyIpLAogICAgbGVnZW5kLm1hcmdpbiA9IG1hcmdpbihjKDAsIDAsIDAsIDApLCB1bml0ID0gImxpbmVzIiksCiAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpCiAgKQoKcGxvdF9zcl9jZW50cmFsaXR5X2luZGl2aWR1YWwKCmlmIChrbml0dGluZykgewogIGdnc2F2ZSgKICAgIGhlcmUoIm91dHB1dHMiLCAiMDcta3JhY2toYXJkdCIsICJzcl9jZW50cmFsaXR5X2luZGl2aWR1YWxfc3RhbmRhcmQucGRmIiksCiAgICBwbG90ID0gcGxvdF9zcl9jZW50cmFsaXR5X2luZGl2aWR1YWwsCiAgICB3aWR0aCA9IDEyLCBoZWlnaHQgPSA4LAogICAgZGV2aWNlID0gY2Fpcm9fcGRmLCB1bml0cyA9ICJpbiIsIGRwaSA9IDMwMAogICkKfQpgYGAKCldlJ3JlIHBhcnRpY3VsYXJseSBpbnRlcmVzdGVkIGluIHRoZSBtYW5hZ2VyIHBhaXJzIDEtNyBhbmQgMTgtMjEuIE9uIGFuIGluZGl2aWR1YWwtYnktaW5kaXZpZHVhbCBiYXNpcywgZG9lcyB0aGUgbW9kZWwgY29ycmVjdGx5IHByZWRpY3QsIGluIGVhY2ggcGFpciwgd2hpY2ggbWFuYWdlciBpcyByZXByZXNlbnRlZCBhcyBiZWluZyBtb3JlIGNlbnRyYWw/IFdlJ2xsIGRvIGEgcHJldmFsZW5jZSB0ZXN0IHRvIHNlZSB3aGV0aGVyIHRoZSBtb2RlbCBtYWRlIGNvcnJlY3QgcHJlZGljdGlvbnMgZm9yIHNpZ25pZmljYW50bHkgZ3JlYXRlciB0aGFuIDUwJSBvZiBzdWJqZWN0cy4KCmBgYHtyIHByZXZhbGVuY2UtdGVzdH0Kc3JfY2VudHJhbGl0eSAlPiUKICAjIEZpbmQgYW5kIHJldGFpbiBvbmx5IHJlbGV2YW50IG5vZGUtcGFpcnMKICBtdXRhdGUoCiAgICBwYWlyX2lkID0gY2FzZV93aGVuKAogICAgICBub2RlX2lkICVpbiUgYygxLCA3KSB+ICIxLTciLAogICAgICBub2RlX2lkICVpbiUgYygxOCwgMjEpIH4gIjE4LTIxIgogICAgKQogICkgJT4lCiAgZHJvcF9uYSgpICU+JQogICMgV2hpY2hldmVyIG1hbmFnZXIgaXMgcmVwcmVzZW50ZWQgYXMgYmVpbmcgbW9yZSBjZW50cmFsIGluIGVhY2ggbm9kZS1wYWlyLAogICMgZG9lcyB0aGUgbW9kZWwgbWFrZSBhIGNvcnJlY3QgcHJlZGljdGlvbj8KICBncm91cF9ieShzdWJfaWQsIHBhaXJfaWQpICU+JQogIG11dGF0ZSgKICAgIGFjcm9zcygKICAgICAgYyhzcl9jZW50cmFsaXR5LCBwZXJjZWl2ZWRfY2VudHJhbGl0eSksCiAgICAgIH4ueCAtIGZpcnN0KC54KQogICAgKQogICkgJT4lCiAgZmlsdGVyKG5vZGVfaWQgJWluJSBjKDcsIDIxKSkgJT4lCiAgc3VtbWFyaXNlKAogICAgY29ycmVjdCA9IHNyX2NlbnRyYWxpdHkgKiBwZXJjZWl2ZWRfY2VudHJhbGl0eSA+IDAsCiAgICAuZ3JvdXBzID0gImRyb3AiCiAgKSAlPiUKICAjIFRhbGx5IGNvcnJlY3QgcHJlZGljdGlvbnMKICBjb3VudChwYWlyX2lkLCBjb3JyZWN0KSAlPiUKICAjIFByZXZhbGVuY2UgdGVzdAogIGZpbHRlcihjb3JyZWN0KSAlPiUKICBzcGxpdCguJHBhaXJfaWQpICU+JQogIG1hcF9kZnIoCiAgICAuZiA9IH4ueCAlPiUKICAgICAgc2VsZWN0KG4pICU+JQogICAgICBkZWZyYW1lKCkgJT4lCiAgICAgIGJpbm9tLnRlc3QoeCA9IC4sIG4gPSAyMSwgcCA9IDAuNSwgYWx0ZXJuYXRpdmUgPSAiZ3JlYXRlciIpICU+JQogICAgICB0aWR5KCksCiAgICAuaWQgPSAicGFpcl9pZCIKICApICU+JQogIGthYmxlKGNhcHRpb24gPSAiUHJldmFsZW5jZSB0ZXN0ICg+IDUwJSkiKQpgYGAKCldlJ2QgcHJldmlvdXNseSBub3RlZCB0aGF0IGJldHdlZW5uZXNzIHNlZW1zIHRvIHRyYWNrIGRpc2NyZXBhbmNpZXMgYmV0d2VlbiBhIG1hbmFnZXIncyB0cnVlIHZlcnN1cyBwZXJjZWl2ZWQgY2VudHJhbGl0eS4gRG9lcyBTUiBjZW50cmFsaXR5IHRyYWNrIHdpdGggYmV0d2Vlbm5lc3M/IFRoZSBsb2VzcyBjdXJ2ZSBzdWdnZXN0cyB0aGUgcmVsYXRpb25zaGlwIGlzIG5vbmxpbmVhciwgYnV0IHRoZXJlIGlzIGEgc3Ryb25nbHkgc2lnbmlmaWNhbnQgcmFuayBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSB0d28uCgpgYGB7ciB0ZXN0LXNyLWJldHdlZW5uZXNzfQpzcl9jZW50cmFsaXR5ICU+JQogIGdyb3VwX2J5KG5hbWUgPSBub2RlX2lkKSAlPiUKICBzdW1tYXJpc2Uoc3JfY2VudHJhbGl0eSA9IG1lYW4oc3JfY2VudHJhbGl0eSkpICU+JQogIGxlZnRfam9pbihjZW50cmFsaXR5X2RpZmZlcmVuY2VzKSAlPiUKICBnZ3Bsb3QoYWVzKHg9c3JfY2VudHJhbGl0eSwgeT1CZXR3ZWVubmVzcykpICsKICBnZyArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxvZXNzIiwgc2UgPSBGQUxTRSkgKwogIGdlb21fbGFiZWwoYWVzKGxhYmVsID0gbmFtZSkpICsKICB4bGFiKCJTdWNjZXNzb3IgUmVwcmVzZW50YXRpb24gXHUwM0IzID0gMC43IikKCmlmIChrbml0dGluZykgewogIGdnc2F2ZSgKICAgIGhlcmUoIm91dHB1dHMiLCAiMDcta3JhY2toYXJkdCIsICJjZW50cmFsaXR5X3NyX3ZzX2JldHdlZW5uZXNzLnBkZiIpLAogICAgd2lkdGggPSA2LCBoZWlnaHQgPSA0LAogICAgZGV2aWNlID0gY2Fpcm9fcGRmLCB1bml0cyA9ICJpbiIsIGRwaSA9IDMwMAogICkKfQoKc3JfY2VudHJhbGl0eSAlPiUKICBncm91cF9ieShuYW1lID0gbm9kZV9pZCkgJT4lCiAgc3VtbWFyaXNlKHNyX2NlbnRyYWxpdHkgPSBtZWFuKHNyX2NlbnRyYWxpdHkpKSAlPiUKICBsZWZ0X2pvaW4oY2VudHJhbGl0eV9kaWZmZXJlbmNlcykgJT4lCiAgd2l0aChjb3IudGVzdChCZXR3ZWVubmVzcywgc3JfY2VudHJhbGl0eSwgbWV0aG9kID0gInNwZWFybWFuIiwgZXhhY3QgPSBGQUxTRSkpICU+JQogIHRpZHkoKSAlPiUKICBrYWJsZShjYXB0aW9uID0gIkJldHdlZW5uZXNzIHZzIFNSIGdhbW1hIDAuNyIpCmBgYAoKCiMgQ29tcGFueSBsZWFkZXJzaGlwCgpTbyBmYXIsIHdlIGhhdmUgbm90IHByb3ZpZGVkIHRoZSBtb2RlbCB3aXRoIGFueSBwcml2aWxlZ2VkIGtub3dsZWRnZSBhYm91dCB0aGUgY29tcGFueSdzIHNlbmlvciBsZWFkZXJzaGlwIGhpZXJhcmNoeS4gWWV0LCB1c2luZyBvYnNlcnZhdGlvbnMgY29uc3RyYWluZWQgYnkgdGhlIG5ldHdvcmsgc3RydWN0dXJlLCB0aGUgbW9kZWwgaGFzIGlkZW50aWZpZWQgbW9zdCBvZiB0aGUgY29tcGFueSdzIGxlYWRlcnNoaXAgYW55d2F5cy4KClRoZSBDRU8gaXMgY29kZWQgYXMgbm9kZSA3LCBhbmQgdGhlIGZvdXIgVmljZSBQcmVzaWRlbnRzIGFyZSBjb2RlZCBhcyAyLCAxNCwgMTgsIGFuZCAyMS4gV2Ugc2VlIGNsZWFyIGV2aWRlbmNlIHRoYXQgdGhlIG1vZGVsIGlkZW50aWZpZXMgbm9kZXMgMiwgNywgMTgsIGFuZCAyMSBhcyBiZWluZyBjZW50cmFsIGZpZ3VyZXMsIGJ1dCB0aGUgbW9kZWwgbWFrZXMgY29uc3BpY3VvdXNseSBpbmNvcnJlY3QgcHJlZGljdGlvbnMgYWJvdXQgbWFuYWdlciAxNC4KCkNvdWxkIHRoZSBtb2RlbCBpbiBwcmluY2lwbGUgZG8gYSBiZXR0ZXIgam9iIGF0IGlkZW50aWZ5aW5nIG1hbmFnZXIgMTQgYXMgYSBjZW50cmFsIG5ldHdvcmsgbWVtYmVyPyBUbyB0ZXN0IHRoaXMsIHdlJ2xsIG1ha2Ugb25lIGFkZGl0aW9uYWwgYXNzdW1wdGlvbiBhYm91dCBtYW5hZ2Vycycgb2JzZXJ2YXRpb25zOiB0aGV5IG9ic2VydmUgdGhlIHNlbmlvciBsZWFkZXJzaGlwIHR3aWNlIGFzIG11Y2ggYXMgb3RoZXIgbmV0d29yayBtZW1iZXJzLgoKYGBge3IgbGVhZGVyc2hpcC1jb21wdXRlLXNyfQpzcl9vYnNlcnZhdGlvbnNfbGVhZGVyc2hpcCA8LSBvYnNfZWRnZWxpc3Rfb3V0ICU+JQogICMgRG91YmxlLWNvdW50IENFTyBhbmQgVlBzCiAgYmluZF9yb3dzKAogICAgb2JzX2VkZ2VsaXN0X291dCAlPiUKICAgICAgZmlsdGVyKGZyb20gJWluJSBjKDIsIDcsIDE0LCAxOCwgMjEpIHwgdG8gJWluJSBjKDIsIDcsIDE0LCAxOCwgMjEpKQogICkgJT4lCiAgZXhwYW5kX2dyaWQocmVwID0gMToxMDApICU+JQogIGdyb3VwX2J5KHN1Yl9pZCwgcmVwKSAlPiUKICBzbGljZV9zYW1wbGUocHJvcCA9IDEpICU+JQogIHVuZ3JvdXAoKQoKc3JfbGVhZGVyc2hpcCA8LSBzcl9vYnNlcnZhdGlvbnNfbGVhZGVyc2hpcCAlPiUKICBleHBhbmRfZ3JpZChnYW1tYSA9IHNlcSgwLjEsIDAuOSwgMC4xKSwgLikgJT4lCiAgZ3JvdXBfYnkoc3ViX2lkLCBnYW1tYSkgJT4lCiAgbmVzdCgpICU+JQogIG11dGF0ZSgKICAgIHNyID0gbWFwMigKICAgICAgLnggPSBkYXRhLCAueSA9IGdhbW1hLAogICAgICB+YnVpbGRfcmVwX3NyKC54LCB0aGlzX2FscGhhID0gMC4xLCB0aGlzX2dhbW1hID0gLnkpCiAgICApCiAgKSAlPiUKICB1bm5lc3Qoc3IpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBzZWxlY3QoLWRhdGEpICU+JQogIG11dGF0ZShnYW1tYSA9IGdhbW1hICogMTApICU+JQogIHBpdm90X3dpZGVyKAogICAgbmFtZXNfZnJvbSA9IGdhbW1hLAogICAgbmFtZXNfcHJlZml4ID0gInNyIiwKICAgIHZhbHVlc19mcm9tID0gc3JfdmFsdWUKICApCmBgYAoKV2UnbGwgdGVzdCB3aGV0aGVyIHRoZSBtb2RlbCBnb29kbmVzcy1vZi1maXQgaXMgYmV0dGVyIGF0ICRcZ2FtbWEgPSAwLjckLCB3aGljaCB3YXMgdGhlIGJlc3QtZml0dGluZyBtb2RlbCBmcm9tIGJlZm9yZToKCmBgYHtyIGxlYWRlcnNoaXAtYmljfQp0ZXN0X3NyN19sZWFkZXJzaGlwIDwtIGtyYWNraGFyZHRfYWxsb2NlbnRyaWMgJT4lCiAgcmVuYW1lKGNob2ljZSA9IGVkZ2UpICU+JQogIGxlZnRfam9pbihzY2hlbWFfZXhwZXJ0c19vdXQsIGJ5ID0gYygic3ViX2lkIiwgImZyb20iLCAidG8iKSkgJT4lCiAgbGVmdF9qb2luKHNyX2xlYWRlcnNoaXAsIGJ5ID0gYygic3ViX2lkIiwgImZyb20iLCAidG8iKSkgJT4lCiAgZ2xtZXIoCiAgICBjaG9pY2UgfiBtZW1fdmFsdWUgKyBzcjcgKyAoMSArIHNyNyB8IHN1Yl9pZCksCiAgICBmYW1pbHkgPSAiYmlub21pYWwiLCBkYXRhID0gLgogICkKCmJpbmRfcm93cygKICBnbGFuY2UodGVzdF9zcjdfb3V0KSAlPiUgbXV0YXRlKG1vZGVsID0gInNyNyBzdGFuZGFyZCIpLAogIGdsYW5jZSh0ZXN0X3NyN19sZWFkZXJzaGlwKSAlPiUgbXV0YXRlKG1vZGVsID0gInNyNyBsZWFkZXJzaGlwIDJ4IikKKSAlPiUKICBrYWJsZSgpCmBgYAoKYGBge3IgbGVhZGVyc2hpcC1jZW50cmFsaXR5fQpzcl9jZW50cmFsaXR5X2xlYWRlcnNoaXAgPC0gc3JfbGVhZGVyc2hpcCAlPiUKICAjIFNSIGNlbnRyYWxpdHkgZnJvbSBiZXN0IHZhcmlhbnQKICBmaWx0ZXIoZnJvbSAhPSB0bykgJT4lCiAgZ3JvdXBfYnkoc3ViX2lkLCBub2RlX2lkID0gdG8pICU+JQogIHN1bW1hcmlzZShzcl9jZW50cmFsaXR5ID0gbWVhbihzcjcpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUKICAjIFBlcmNlaXZlZCBjZW50cmFsaXR5CiAgbGVmdF9qb2luKAogICAga3JhY2toYXJkdF9hbGxvY2VudHJpYyAlPiUKICAgICAgZ3JvdXBfYnkoc3ViX2lkLCBub2RlX2lkID0gdG8pICU+JQogICAgICBzdW1tYXJpc2UocGVyY2VpdmVkX2NlbnRyYWxpdHkgPSBtZWFuKGVkZ2UpLCAuZ3JvdXBzID0gImRyb3AiKSwKICAgIGJ5ID0gYygic3ViX2lkIiwgIm5vZGVfaWQiKQogICkKCnNyX2NlbnRyYWxpdHlfY29ycl9sZWFkZXJzaGlwIDwtIHNyX2NlbnRyYWxpdHlfbGVhZGVyc2hpcCAlPiUKICBncm91cF9ieShzdWJfaWQpICU+JQogIG5lc3QoKSAlPiUKICBtdXRhdGUoCiAgICBzcGVhcm1hbiA9IG1hcF9kYmwoCiAgICAgIC54ID0gZGF0YSwKICAgICAgLmYgPSB+d2l0aCgKICAgICAgICAueCwgY29yKAogICAgICAgICAgc3JfY2VudHJhbGl0eSwgcGVyY2VpdmVkX2NlbnRyYWxpdHksIG1ldGhvZCA9ICJzcGVhcm1hbiIKICAgICAgICApCiAgICAgICkKICAgICkKICApICU+JQogIHVuZ3JvdXAoKSAlPiUKICBzZWxlY3QoLWRhdGEpCgpzcl9jZW50cmFsaXR5X2NvcnJfbGVhZGVyc2hpcCAlPiUKICBtdXRhdGUoc3BlYXJtYW4gPSBhdGFuaChzcGVhcm1hbikpICU+JQogIHNlbGVjdChzcGVhcm1hbikgJT4lCiAgZGVmcmFtZSgpICU+JQogIHQudGVzdCgpICU+JQogIHRpZHkoKSAlPiUKICBrYWJsZSgKICAgIGNhcHRpb24gPSBzdHJfYygKICAgICAgInQtdGVzdCBvZiB0aGUgYXZlcmFnZSBTcGVhcm1hbiBjb3JyZWxhdGlvbiBiZXR3ZWVuIHBlcmNlaXZlZCBhbmQgIiwKICAgICAgIlNSLXByZWRpY3RlZCBjZW50cmFsaXR5ICh6LXRyYW5zZm9ybWVkKSIKICAgICkKICApCgpzcl9jZW50cmFsaXR5X2NvcnJfbGVhZGVyc2hpcCAlPiUKICBzdW1tYXJpc2UobWVhbl9zcGVhcm1hbiA9IG1lYW4oc3BlYXJtYW4pKSAlPiUKICBrYWJsZSgpCmBgYAoKYGBge3IgbGVhZGVyc2hpcC1wbG90LWNlbnRyYWxpdHl9CnBsb3Rfc3JfY2VudHJhbGl0eV9ncm91cF9sZWFkZXJzaGlwIDwtIHNyX2NlbnRyYWxpdHlfbGVhZGVyc2hpcCAlPiUKICAjIEdldCBlYWNoIHN1YmplY3QncyByYW5rLW9yZGVyZWQgcGVyY2VpdmVkIGFuZCBTUi1wcmVkaWN0ZWQgY2VudHJhbGl0eQogIGdyb3VwX2J5KHN1Yl9pZCkgJT4lCiAgbXV0YXRlKGFjcm9zcyhlbmRzX3dpdGgoIl9jZW50cmFsaXR5IiksIH5yYW5rKC54LCB0aWVzLm1ldGhvZCA9ICJtaW4iKSkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICAjIEF2ZXJhZ2UgYWNyb3NzIHN1YmplY3RzIHRvIGdldCBncm91cC1sZXZlbCByZXN1bHRzCiAgZ3JvdXBfYnkobm9kZV9pZCkgJT4lCiAgc3VtbWFyaXNlKGFjcm9zcyhlbmRzX3dpdGgoIl9jZW50cmFsaXR5IiksIG1lYW4pKSAlPiUKICAjIEZvciBjb2xvci1jb2RpbmcgdHdvIHBhaXJzIG9mIG1hbmFnZXJzIHdpdGggZXF1aXZhbGVudCBkZWdyZWUgY2VudHJhbGl0eSwKICAjIGJ1dCBkaWZmZXJlbnQgcGVyY2VpdmVkIGNlbnRyYWxpdHkKICBtdXRhdGUoCiAgICBjb2xvcmNvZGUgPSBjYXNlX3doZW4oCiAgICAgIG5vZGVfaWQgJWluJSBjKDEsIDcpIH4gImEiLAogICAgICBub2RlX2lkICVpbiUgYygxOCwgMjEpIH4gImIiCiAgICApCiAgKSAlPiUKICBnZ3Bsb3QoYWVzKHg9cGVyY2VpdmVkX2NlbnRyYWxpdHksIHk9c3JfY2VudHJhbGl0eSkpICsKICBnZyArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sb3IgPSAiYmxhY2siKSArCiAgZ2VvbV9sYWJlbChhZXMobGFiZWwgPSBub2RlX2lkLCBmaWxsID0gY29sb3Jjb2RlKSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNhNmNlZTMiLCAiI2IyZGY4YSIpLCBuYS52YWx1ZSA9ICJncmV5OTUiKSArCiAgc2NhbGVfeF9jb250aW51b3VzKG5hbWUgPSAiUGVyY2VpdmVkIGNlbnRyYWxpdHkgKHJhbmstb3JkZXJlZCkiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKG5hbWUgPSAiU1IgY2VudHJhbGl0eSAocmFuay1vcmRlcmVkKSIpICsKICBnZ3RpdGxlKCJQZXJjZWl2ZWQgdnMgU3VjY2Vzc29yIENlbnRyYWxpdHkgKEdyb3VwLUxldmVsKSIpCgpwbG90X3NyX2NlbnRyYWxpdHlfZ3JvdXBfbGVhZGVyc2hpcAoKcGxvdF9zcl9jZW50cmFsaXR5X2luZGl2aWR1YWxfbGVhZGVyc2hpcCA8LSBzcl9jZW50cmFsaXR5X2xlYWRlcnNoaXAgJT4lCiAgIyBHZXQgZWFjaCBzdWJqZWN0J3MgcmFuay1vcmRlcmVkIHBlcmNlaXZlZCBhbmQgU1ItcHJlZGljdGVkIGNlbnRyYWxpdHkKICBncm91cF9ieShzdWJfaWQpICU+JQogIG11dGF0ZShhY3Jvc3MoZW5kc193aXRoKCJfY2VudHJhbGl0eSIpLCB+cmFuaygueCwgdGllcy5tZXRob2QgPSAibWluIikpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgIyBGb3JtYXR0aW5nIGZvciBwbG90dGluZwogIHBpdm90X2xvbmdlcigKICAgIGVuZHNfd2l0aCgiX2NlbnRyYWxpdHkiKSwKICAgIG5hbWVzX3RvID0gIm1ldHJpYyIsCiAgICB2YWx1ZXNfdG8gPSAiY2VudHJhbGl0eSIKICApICU+JQogIG11dGF0ZSgKICAgIG5vZGVfaWQgPSBmYWN0b3Iobm9kZV9pZCksCiAgICBzdWJfaWQgPSBzdHJfcGFkKHN1Yl9pZCwgd2lkdGggPSAyLCBzaWRlID0gImxlZnQiLCBwYWQgPSAiMCIpLAogICAgc3ViX2lkID0gc3RyX2MoIk1hbmFnZXIgIiwgc3ViX2lkKQogICkgJT4lCiAgZ2dwbG90KGFlcyh4PW5vZGVfaWQsIHk9Y2VudHJhbGl0eSwgZmlsbD1tZXRyaWMpKSArCiAgZmFjZXRfd3JhcCh+c3ViX2lkLCBucm93ID0gMykgKwogIGdlb21fY29sKHBvc2l0aW9uID0gImlkZW50aXR5IiwgY29sb3IgPSAiYmxhY2siLCBhbHBoYSA9IDAuNSkgKwogIGNvb3JkX3BvbGFyKCkgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19kKAogICAgbmFtZSA9ICJDZW50cmFsaXR5IiwKICAgIGxhYmVscyA9IGMoIlBlcmNlaXZlZCAoRW1waXJpY2FsKSIsICJTdWNjZXNzb3IgUmVwcmVzZW50YXRpb24gKFNpbXVsYXRlZCkiKQogICkgKwogIGdndGl0bGUoIlBlcmNlaXZlZCB2cyBTdWNjZXNzb3IgQ2VudHJhbGl0eSAoSW5kaXZpZHVhbC1MZXZlbCkiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTMpLAogICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDExKSwKICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5zcGFjaW5nID0gdW5pdCgwLjc1LCAibGluZXMiKSwKICAgIGxlZ2VuZC5ib3guc3BhY2luZyA9IHVuaXQoMC41LCAibGluZXMiKSwKICAgIGxlZ2VuZC5tYXJnaW4gPSBtYXJnaW4oYygwLCAwLCAwLCAwKSwgdW5pdCA9ICJsaW5lcyIpLAogICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKQogICkKCnBsb3Rfc3JfY2VudHJhbGl0eV9pbmRpdmlkdWFsX2xlYWRlcnNoaXAKCmlmIChrbml0dGluZykgewogIGdnc2F2ZSgKICAgIGhlcmUoIm91dHB1dHMiLCAiMDcta3JhY2toYXJkdCIsICJzcl9jZW50cmFsaXR5X2dyb3VwX2xlYWRlcnNoaXAucGRmIiksCiAgICBwbG90ID0gcGxvdF9zcl9jZW50cmFsaXR5X2dyb3VwX2xlYWRlcnNoaXAsCiAgICB3aWR0aCA9IDYsIGhlaWdodCA9IDQsCiAgICBkZXZpY2UgPSBjYWlyb19wZGYsIHVuaXRzID0gImluIiwgZHBpID0gMzAwCiAgKQogIAogIGdnc2F2ZSgKICAgIGhlcmUoIm91dHB1dHMiLCAiMDcta3JhY2toYXJkdCIsICJzcl9jZW50cmFsaXR5X2luZGl2aWR1YWxfbGVhZGVyc2hpcC5wZGYiKSwKICAgIHBsb3QgPSBwbG90X3NyX2NlbnRyYWxpdHlfaW5kaXZpZHVhbF9sZWFkZXJzaGlwLAogICAgd2lkdGggPSAxMiwgaGVpZ2h0ID0gOCwKICAgIGRldmljZSA9IGNhaXJvX3BkZiwgdW5pdHMgPSAiaW4iLCBkcGkgPSAzMDAKICApCn0KYGBgCgojIEZpZ3VyZXMgZm9yIHBhcGVyCgpgYGB7ciBwYXBlci1uZXR3b3JrLWdyYXBofQpuZXR3b3JrX2Zvcl9wYXBlciA8LSBrcmFja2hhcmR0X2cgJT4lCiAgbXV0YXRlKAogICAgRGVncmVlID0gY2VudHJhbGl0eV9kZWdyZWUobW9kZSA9ICJpbiIpLAogICAgbm9kZV9jb2xvcmNvZGUgPSBjYXNlX3doZW4oCiAgICAgIG5hbWUgJWluJSBjKDEsIDcpIH4gImEiLAogICAgICBuYW1lICVpbiUgYygxOCwgMjEpIH4gImIiCiAgICApCiAgKSAlPiUKICAjIFRvIGNsZWFuIHVwIHNvbWUgb2YgdGhlIG92ZXJwbG90dGluZwogIGFjdGl2YXRlKCJlZGdlcyIpICU+JQogIG11dGF0ZSgKICAgIGVkZ2VfY29sb3Jjb2RlID0gY2FzZV93aGVuKAogICAgICBmcm9tICVpbiUgYygxLCA3KSB8IHRvICVpbiUgYygxLCA3KSB+ICJhIiwKICAgICAgZnJvbSAlaW4lIGMoMTgsIDIxKSB8IHRvICVpbiUgYygxOCwgMjEpIH4gImIiCiAgICApCiAgKSAlPiUKICAjIFBsb3QgdGhlICJncm91bmQgdHJ1dGgiIG5ldHdvcmsKICBnZ3JhcGgobGF5b3V0ID0gInN0cmVzcyIpICsKICBnZW9tX2VkZ2VfbGluaygKICAgIGFlcygKICAgICAgc3RhcnRfY2FwID0gbGFiZWxfcmVjdChub2RlMS5uYW1lLCBwYWRkaW5nID0gbWFyZ2luKDE1LCAxNSwgMTUsIDE1KSksCiAgICAgIGVuZF9jYXAgPSBsYWJlbF9yZWN0KG5vZGUyLm5hbWUsIHBhZGRpbmcgPSBtYXJnaW4oMTUsIDE1LCAxNSwgMTUpKSwKICAgICAgY29sb3IgPSBlZGdlX2NvbG9yY29kZQogICAgKSwKICAgIGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCg1LCAicHQiKSwgdHlwZSA9ICJjbG9zZWQiKSwKICAgIHNob3cubGVnZW5kID0gRkFMU0UKICApICsKICBnZW9tX25vZGVfbGFiZWwoCiAgICBhZXMobGFiZWwgPSBuYW1lLCBzaXplID0gRGVncmVlLCBmaWxsID0gbm9kZV9jb2xvcmNvZGUpLAogICAgc2hvdy5sZWdlbmQgPSBGQUxTRQogICkgKwogIHNjYWxlX3NpemUocmFuZ2UgPSBjKDMsIDEwKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNhNmNlZTMiLCAiI2IyZGY4YSIpLCBuYS52YWx1ZSA9ICJncmV5OTUiKSArCiAgc2NhbGVfZWRnZV9jb2xvcl9tYW51YWwoCiAgICB2YWx1ZXMgPSBjKCIjMWY3OGI0IiwgIiMzM2EwMmMiKSwgbmEudmFsdWUgPSAiZ3JleTgwIgogICkgKwogIGdndGl0bGUoIkFkdmljZSBOZXR3b3JrIChLcmFja2hhcmR0IDE5ODcpIikgKwogIHRoZW1lKAogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxMyksCiAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTMpLAogICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIKICApCgpuZXR3b3JrX2Zvcl9wYXBlcgoKaWYgKGtuaXR0aW5nKSB7CiAgZ2dzYXZlKAogICAgaGVyZSgib3V0cHV0cyIsICIwNy1rcmFja2hhcmR0IiwgIm5ldHdvcmtfZ3JhcGgucGRmIiksCiAgICBwbG90ID0gbmV0d29ya19mb3JfcGFwZXIsCiAgICB3aWR0aCA9IDEyLCBoZWlnaHQgPSA1LAogICAgZGV2aWNlID0gY2Fpcm9fcGRmLCB1bml0cyA9ICJpbiIsIGRwaSA9IDMwMAogICkKfQpgYGAKCmBgYHtyIHBhcGVyLXJlcHJlc2VudGF0aW9ufQpyZXByZXNlbnRhdGlvbl9mb3JfcGFwZXIgPC0gKAogIChwbG90X2Nob2ljZSArIGdndGl0bGUoIlBlcmNlaXZlZCAoRW1waXJpY2FsKSIpKSB8CiAgICBwbG90X3NyN19vdXQgKyBnZ3RpdGxlKCJTdWNjZXNzb3IgUmVwLiBcdTAzQjMgPSAwLjcgKFNpbXVsYXRlZCkiKQopICsKICBwbG90X2Fubm90YXRpb24oCiAgICB0aXRsZSA9ICJOZXR3b3JrIFJlcHJlc2VudGF0aW9uIiwKICAgIHRoZW1lID0gdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTMsIGhqdXN0ID0gMC41KSkKICApCgpyZXByZXNlbnRhdGlvbl9mb3JfcGFwZXIKCmlmIChrbml0dGluZykgewogIGdnc2F2ZSgKICAgIGhlcmUoIm91dHB1dHMiLCAiMDcta3JhY2toYXJkdCIsICJyZXByZXNlbnRhdGlvbi5wZGYiKSwKICAgIHBsb3QgPSByZXByZXNlbnRhdGlvbl9mb3JfcGFwZXIsCiAgICB3aWR0aCA9IDEyLCBoZWlnaHQgPSA1LAogICAgZGV2aWNlID0gY2Fpcm9fcGRmLCB1bml0cyA9ICJpbiIsIGRwaSA9IDMwMAogICkKfQpgYGAKCmBgYHtyIHBhcGVyLWNlbnRyYWxpdHl9CmNlbnRyYWxpdHlfaW5kaXZpZHVhbF9mb3JfcGFwZXIgPC0gc3JfY2VudHJhbGl0eSAlPiUKICBmaWx0ZXIoc3ViX2lkICVpbiUgYygxNywgMTkpKSAlPiUKICAjIEdldCBlYWNoIHN1YmplY3QncyByYW5rLW9yZGVyZWQgcGVyY2VpdmVkIGFuZCBTUi1wcmVkaWN0ZWQgY2VudHJhbGl0eQogIGdyb3VwX2J5KHN1Yl9pZCkgJT4lCiAgbXV0YXRlKGFjcm9zcyhlbmRzX3dpdGgoIl9jZW50cmFsaXR5IiksIH5yYW5rKC54LCB0aWVzLm1ldGhvZCA9ICJtaW4iKSkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICAjIEZvcm1hdHRpbmcgZm9yIHBsb3R0aW5nCiAgcGl2b3RfbG9uZ2VyKAogICAgZW5kc193aXRoKCJfY2VudHJhbGl0eSIpLAogICAgbmFtZXNfdG8gPSAibWV0cmljIiwKICAgIHZhbHVlc190byA9ICJjZW50cmFsaXR5IgogICkgJT4lCiAgbXV0YXRlKAogICAgbm9kZV9pZCA9IGZhY3Rvcihub2RlX2lkKSwKICAgIHN1Yl9pZCA9IHN0cl9wYWQoc3ViX2lkLCB3aWR0aCA9IDIsIHNpZGUgPSAibGVmdCIsIHBhZCA9ICIwIiksCiAgICBzdWJfaWQgPSBzdHJfYygiTWFuYWdlciAiLCBzdWJfaWQpCiAgKSAlPiUKICBnZ3Bsb3QoYWVzKHg9bm9kZV9pZCwgeT1jZW50cmFsaXR5LCBmaWxsPW1ldHJpYykpICsKICBmYWNldF93cmFwKH5zdWJfaWQpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJpZGVudGl0eSIsIGNvbG9yID0gImJsYWNrIiwgYWxwaGEgPSAwLjUpICsKICBjb29yZF9wb2xhcigpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfZCgKICAgIG5hbWUgPSAiQ2VudHJhbGl0eSIsCiAgICBsYWJlbHMgPSBjKCJQZXJjZWl2ZWQgKEVtcGlyaWNhbCkiLCAiU3VjY2Vzc29yIFJlcC4gKFNpbXVsYXRlZCkiKQogICkgKwogIGdndGl0bGUoIkluZGl2aWR1YWwtTGV2ZWwiKSArCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTMpLAogICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDExKSwKICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5zcGFjaW5nID0gdW5pdCgwLjc1LCAibGluZXMiKSwKICAgIGxlZ2VuZC5ib3guc3BhY2luZyA9IHVuaXQoMC41LCAibGluZXMiKSwKICAgIGxlZ2VuZC5tYXJnaW4gPSBtYXJnaW4oYygwLCAwLCAwLCAwKSwgdW5pdCA9ICJsaW5lcyIpLAogICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKQogICkKCmNlbnRyYWxpdHlfZm9yX3BhcGVyIDwtICgKICAoCiAgICBwbG90X3NyX2NlbnRyYWxpdHlfZ3JvdXAgKwogICAgICBnZ3RpdGxlKCJHcm91cC1MZXZlbCIpICsKICAgICAgc2NhbGVfeV9jb250aW51b3VzKG5hbWUgPSAiU3VjY2Vzc29yIFJlcC4gY2VudHJhbGl0eSAocmFuay1vcmRlcmVkKSIpCiAgKSB8CiAgICBjZW50cmFsaXR5X2luZGl2aWR1YWxfZm9yX3BhcGVyCikgKwogIHBsb3RfYW5ub3RhdGlvbigKICAgIHRpdGxlID0gIlBlcmNlaXZlZCB2cyBTdWNjZXNzb3IgQ2VudHJhbGl0eSIsCiAgICB0aGVtZSA9IHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEzLCBoanVzdCA9IDAuNSkpCiAgKQoKY2VudHJhbGl0eV9mb3JfcGFwZXIKCmlmIChrbml0dGluZykgewogIGdnc2F2ZSgKICAgIGhlcmUoIm91dHB1dHMiLCAiMDcta3JhY2toYXJkdCIsICJjZW50cmFsaXR5LnBkZiIpLAogICAgcGxvdCA9IGNlbnRyYWxpdHlfZm9yX3BhcGVyLAogICAgd2lkdGggPSAxMiwgaGVpZ2h0ID0gNSwKICAgIGRldmljZSA9IGNhaXJvX3BkZiwgdW5pdHMgPSAiaW4iLCBkcGkgPSAzMDAKICApCn0KYGBgCgoKIyBTYXZlIGRhdGEKCkl0IHdhcyBhIGJpdCBvZiBhIHBhaW4gZ2V0dGluZyB0aGUgcmF3IGRhdGEgaW50byBzaGFwZSwgc28gd2UnbGwgc2F2ZSB0aGUgY2xlYW5lZCB2ZXJzaW9ucyBmb3IgcG9zdGVyaXR5LgoKYGBge3Igc2F2ZS1kYXRhfQppZiAoa25pdHRpbmcpIHsKICBrcmFja2hhcmR0X2Vnb2NlbnRyaWMgJT4lCiAgICB3cml0ZV9jc3YoaGVyZSgiZGF0YSIsICJrcmFja2hhcmR0IiwgImNsZWFuX2Vnb2NlbnRyaWMuY3N2IikpCiAgCiAga3JhY2toYXJkdF9hbGxvY2VudHJpYyAlPiUKICAgIHJlbmFtZShjaG9pY2UgPSBlZGdlKSAlPiUKICAgIHdyaXRlX2NzdihoZXJlKCJkYXRhIiwgImtyYWNraGFyZHQiLCAiY2xlYW5fYWxsb2NlbnRyaWMuY3N2IikpCn0KYGBgCgoKIyBTZXNzaW9uIGluZm8KCmBgYHtyIHNlc3Npb24taW5mb30Kc2Vzc2lvbkluZm8oKQpgYGAKCg==